丁勇 Email:18442056@QQ.com
学习目标 掌握 Spring 依赖注入的原理 掌握 Spring AOP 原理
Spring 之父 Rod Johnson SpringFramework 创始人, interface21 CEO 丰富的 c/c++ 背景, 丰富的金融行业背景 1996 年开始关注 Java 服务器端技术 Servlet2.4 和 JDO2.0 专家组成员 2002 年著写 Expoert one-on-one J2EE 设计与开发, 改变了 Java 世界 技术主张 : 技术实用为本 音乐学博士
Spring 的绿草丛 Spring : 轻量级框架, Java EE 的春天, 当前主流框架 目标 : 使现有技术更加易用, 推进编码最佳实践 内容 : 依赖注入容器,AOP 实现 ( 声明式事务 ), DAO/ORM 支持,Web 集成
为什么使用依赖注入 (DI) 过于 复杂的软件系统 组件化的思想 目的 : 解耦合 实现每个组件块时只关注组件内部的事情 依赖注入 : 强制将组件的构建和使用分开 组件的使用 接口的定义 要点 : 明确定义组件间的接口 面向对象使系统的实现变得容易 运行时注入 当系统复杂到一定程度时, 仅仅面向组件的生产对象就不够了
怎样使用依赖注入 如何开发一个打印机? 打印机功能的实现依赖于墨盒和纸张 步骤 : 1 定义墨盒和纸张的接口标准 2 使用接口标准开发打印机 3 组装打印机 双色墨盒 4 运行打印机 彩色墨盒 A4 B5
1. 定义组件接口 墨盒接口 :Ink 纸张接口 :Page 怎样使用依赖注入 2. public 使用接口开发打印机 class Printer { public interface Ink { public String getcolor(int r,int g,int b); public interface Paper { public Ink ink = null; public static 我们在开发打印机 final String newline = "\r\n"; 时, 使用了 Ink 和 public Paper paper = null; Paper 接口 但并 public void print(string str){ /** 不关心其实现 System.out.println(" * 输出字符到纸张使用 "+ ink.getcolor(255, */ 200, 0).+" 颜色打印 "); for(int i=0;i<str.length();++i){// public void putinchar(char 逐字符输出到纸张 c); ink 和 paper 何时 paper.putinchar(str.charat(i)); /** 被实例化呢? * 得到输出到纸张上的内容 System.out.print(paper.getContent()); */ // 将纸张的内容输出 public String getcontent();
怎样使用依赖注入 3 组装打印机 1 为了方便组装, 我们给 Printer 类的 ink 和 paper 属性增加 setter 方法 2 public 创建或得到 class Printer Ink 和 Paper 的实现类相当于 { : 3 使用 Spring public 进行组装 Ink ink ColorInk = 相当于 null; colorink : = new 编辑 applicationcontext.xml TextPaper public Paper ColorInk(); paper 文件 a4paper = new = null; TextPaper();...... a4paper.setcharperline(10); public void setink(ink a4paper.setlineperpage(8); ink) { this.ink = ink; public void setpaper(paper paper) { this.paper = paper; 依赖注入给项目添加 Spring 支持
组装打印机 <bean id="b5paper" 依赖注入 : 组装打印机 class="com.aptech.jb.paper.textpaper"> <bean id="greyink" <property name="charperline" value="6" /> class="com.aptech.jb.ink.greyink" <property name="lineperpage" /> value="5" /> B5 A4 </bean> 双色墨盒 <bean id="colorink" <bean id="a4paper" class="com.aptech.jb.paper.textpaper"> <property name="charperline" class="com.aptech.jb.ink.colorink" /> value="10" /> <property name="lineperpage" <bean value="8" id="printer" /> 彩色墨盒 </bean> class="com.aptech.jb.printer"> <property name="ink" ref="colorink"/> <property name="paper"
4. 运行打印机 怎样使用依赖注入 public static void main(string[] args){ ApplicationContext context = new ClassPathXmlApplicationContext( "applicationcontext.xml"); // 由 Spring 创建配置为使用 printer 对象 greyink, 并根据配置文件注入 // 依赖的组件, a4paper 完成组装时的运行结果配置为使用 colorink Printer printer = 通过 Spring: b5paper (Printer)context.getBean("printer"); 时的运行结果我们可以象更换打 printer.print(" 几位轻量级容器的作者曾骄傲地对我印机的墨盒和打印..."); 纸一样地更换程序组件 这就是依赖注入带来的魔力!!
项目中应用依赖注入 使用依赖注入组装原有系统 private XDAO xdao = null; public void setxdao(xdao dao){ xdao = dao; action action biz biz DAO DAO 依赖 依赖 以前的系统 不再依赖具体实现类 通过 setter 方 <beans> 法运行时注入 <!-- DAO --> <bean id="userdao" class="...userdaojdbcimpl" /> <!-- Biz --> 将组件的实 <bean id="userbiz" 自从有了依赖注入现类硬编码 XDAO xdao class="...userbizimpl"> = new <property name="userdao" XDAOJdbcImpl(); ref="userdao"/> </bean> </beans> 现在的系统
小结 编写 gbeens.xml, 使下面的程序输出 : 张嘎说 : 三天不打小鬼子, 手都痒痒 public static void main(string[] args){ ApplicationContext context = public class Greeting { new private String person ; ClassPathXmlApplicationContext("gbeens.xml"); private String words ; Greeting g = (Greeting)context.getBean("g"); public String setperson(string p){ g. saygreeting(); persion = p; public String setwords(string w){ words = w; public void saygreeting(){ System.out.println(person + " 说 :" + words);
面向方面编程 (AOP) Spring 带来的好处 : 让我们可以 专心做事 依赖注入 (DI) 面向方面编程 (AOP) 怎样实现的呢? 编写程序时不用关心其依赖的组件 将程序中涉及的公共问题集中解决
哪些 方面 需要关注 : Aspect: 方面 public void dosamebusiness (long lparam,string sparam){ // 记录日志 log.info(" 调用 dosamebusiness 方法, 参数是 :"+lparam); // 输入合法性验证 if (lparam<=0){ throws new IllegalArgumentException("xx 应该大于 0"); if (sparam==null sparam.trim().equals("")){ 怎样才能 专心 做 throws new IllegalArgumentException("xx 不能为空 "); 事? // 异常处理我们构建系统的目 try{... 注意力被分散的是解决业务问题了, 业务代码质 catch(...){ 量得不到保障 catch(...){ 在编码实现业务逻 辑前, 需要先解决这些方面又都是 // 事务控制如此繁多而且复杂不可或缺的, 绝 tx.commit(); 的多个方面的事情不能丢开不管 这正是 AOP 要解决的问题, Follow me!
怎样使用 AOP 使用 AOP 方式实现日志系统 业务介绍 : 将业务逻辑层每个方法的调用时间和参数输出到控制台 AOP 思路 : 分别编写业务逻辑代码和 方面 代码, 运行时再组装 1 编写业务逻辑接口和实现类, 不用关心 方面 只需要编写业务逻辑相关的代码
怎样使用 AOP 2 编写方面代码, 实现 MethodBeforeAdvice 接口 将要执行的方法, 参数和对应的对象 编写前置通知需要实现 MethodBeforeAdvice 接口 描述 方面 逻辑的代码 Advice: 通知通知, 定义一个 方面方面 要实现的功能 通过配置, 分前置通知 后置通知 环绕通知和异常通知等类型 前置通知中的代码将在方法调用前自动执行
怎样使用 AOP 3 组装 target: 目标, 被代理的 bean, 包含业务代码代理类 : 最终通过代理类访问业务逻辑通知 bean: 包含 方面 代码 将 业务逻辑代码 和 方面代码 组装进代理类 采用代理的方式
怎样使用 AOP 4 运行面向接口编程, 不涉及具体实现类 得到的是代理类的实例 方法调用前自动执行了 方面 代码
小结 AOP 目标 : 专心做事 AOP 原理 将散布在系统中的公共功能集中解决 AOP 实现 采用一个机制 1. 将复杂的需求分解出不同方面 2. 专心做事 3. 组装起来运行
Spring 的 AOP 机制 小结 在方法调用前 后 环绕或抛出异常时, 织入 方面代码 通过代理访问被代理的类 前置通知 环绕通知 方法执行 后置通知 代理 原 Bean 通知 (Advice)
小结 在线购书系统中, 要求不修改 BookBizImpl 代码的情况下增加如下功能 : 对买书的用户进行返利 : 每买一册书返利 3 元 即 : 每调用一次 buy 方法打印 : [ 销售返利 ][ 时提示 : 1. 间返利是在购书成功后进行的 ] 用户名 : 3 元, 因此应该使用后置通知 1. 返利是在购书成功后进行的, 因此应该使用后置通知 2. 后置通知范例 : public class RakeOffAdvice implements AferReturningAdvice{ public void afterreturning(object returnvalue,method m, Object[] args,object target) throws Throwable{ //TODO:your code here
总结 Spring 包含哪些内容? 依赖注入容器 AOP 实现 DAO/ORM 支持 Web 集成 依赖注入的好处是? 分离组件的使用和实现 Spring 怎么实现依赖注入? 添加 getter/setter 方法, 使用配置文件组装 面向方面编程 的好处是? 将 方面 分离出来, 写代码时只需关注当前业务逻辑 Spring 怎么实现 AOP? 在方法调用前 后或抛出异常时 织入 方面代码