Spring3开发实战 之 第三章:AOP开发(1)

AOP是什么(Aspect   Oriented   Programming)
AOP是一种编程范式,提供从另一个角度来考虑程序结构以完善面向对象编程(OOP)。
AOP为开发者提供了一种描述横切关注点的机制,并能够自动将横切关注点织入到面向对象的软件系统中,从而实现了横切关注点的模块化。
 AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理、日志管理、权限控制等,封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
AOP能干什么,也是AOP带来的好处
1:降低模块的耦合度
2:使系统容易扩展
3:设计决定的迟绑定:使用AOP,设计师可以推迟为将来的需求作决定,因为它
可以把这种需求作为独立的方面很容易的实现。
4:更好的代码复用性
  
仍然存在问题:
大家会发现,需要修改的地方分散在很多个文件中,如果需要修改的文件多那么修改的量会很大,这无疑会增加出错的几率,并且加大系统维护的难度。
而且,如果添加功能的需求是在软件开发的后期才提出的话,这样大量修改已有的文件,也不符合基本的“开-闭原则”。
 
改进的解决方案
采用装饰器模式或者代理模式来实现。
 
装饰器模式定义
动态地给一个对象添加一些额外的职责。就增加功能来说, 装饰器模式相比生成子类更为灵活。
代理模式定义
为其他对象提供一种代理以控制对这个对象的访问
 
JDK动态代理解决方案(比较通用的解决方案)

java代码:
  1. public class MyInvocationHandler implements InvocationHandler {  
  2.     private Object target;  
  3.     public MyInvocationHandler(Object target) {  
  4.         this.target = target;  
  5.     }  
  6.     public Object invoke(Object proxy, Method method, Object[] args)  
  7. throws Throwable {  
  8.         //1.记录日志    2.时间统计开始      3.安全检查  
  9.         Object retVal = method.invoke(target, args);  
  10.         //4.时间统计结束  
  11.         return retVal;    
  12.     }  
  13.     public Object proxy() {  
  14.         return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
  15.                 target.getClass().getInterfaces(), new MyInvocationHandler(target));  
  16.     }  
  17. }  
CGLIB动态代理的解决方案:

java代码:
  1. public class MyInterceptor implements MethodInterceptor  {  
  2.     private Object target;  
  3.     public MyInterceptor(Object target) {  
  4.         this.target = target;  
  5.     }  
  6.     public Object intercept(Object proxy, Method method, Object[] args,  
  7.                             MethodProxy invocation) throws Throwable {  
  8.         //1.记录日志 2.时间统计开始   3.安全检查  
  9.         Object retVal = invocation.invoke(target, args);  
  10.         //4.时间统计结束  
  11.         return retVal;    
  12.     }  
  13.     public Object proxy() {  
  14.         return Enhancer.create(target.getClass(), new MyInterceptor(target));  
  15.     }  
  16. }  
JDK动态代理的特点
不能代理类,只能代理接口
CGLIB动态代理的特点
能代理类和接口,不能代理final类
动态代理的本质
用来实现对目标对象进行增强,最终表现为类,只不过是动态创建子类,不用手工生成子类。
 
动态代理的限制
只能在父类方法被调用之前或之后进行增强(功能的修改),不能在中间进行修改,要想在方法调用中增强,需要ASM(一个Java 字节码操作和分析框架)
更好的解决方案——AOP提供
人们认识到,传统的程序经常表现出一些不能自然地适合跨越多个程序模块的行为,例如日志记录、对上下文敏感的错误处理等等,人们将这种行为称为“横切关注点(CrossCuttingConcern)”,因为它跨越了给定编程模型中的典型职责界限。
如果使用过用于密切关注点的代码,您就会知道缺乏模块性所带来的问题。因为横切行为的实现是分散的,开发人员发现这种行为难以作逻辑思维、实现和更改。因此,面向方面的编程AOP应运而生。
 
回过头来再次理解AOP的概念。
关注点
就是所关注的公共功能,比如像事务管理,就是一个关注点。表示  “要做什么”
连接点(Joinpoint)
在程序执行过程中某个特定的点,通常在这些点需要添加关注点的功能,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是代表一个方法的执行。表示  “在什么地方做”
通知(Advice):
在切面的某个特定的连接点(Joinpoint)上执行的动作。
通知有各种类型,其中包括“around”、“before”和“after”等通知。 通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。表示  “具体怎么做”
切面/方面(Aspect)
一个关注点的模块化,这个关注点可能会横切多个对象。  综合表示    在什么地方,要  做什么,以及具体如何做 
切入点(Pointcut):
匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。
目标对象(Target Object):
被一个或者多个切面所通知(advise)的对象。也有人把它叫做 被通知(advised) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。
AOP代理(AOP Proxy):
 AOP框架使用代理模式创建的对象,从而实现在连接点处插入通知(即应用切面),就是  通过代理来对目标对象应用切面。在Spring中,AOP代理可以用JDK动态代理或CGLIB代理实现,而通过拦截器模型应用切面。 注意:Spring引入的基于模式(schema-based)风格和@AspectJ注解风格的切面声明,对于使用这些风格的用户来说,代理的创建是透明的。
 
 
织入(Weaving)
把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象的过程。也就是说织入是一个过程,是将切面应用到目标对象从而创建出AOP代理对象的过程。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
引入(Introduction):
也被称为内部类型声明(inter-type declaration)。为已有的类声明额外的方法或者某个类型的字段。 Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。 例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。
前置通知(Before advice):
在某连接点之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
返回后通知(After returning advice):
在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
抛出异常后通知(After throwing advice):
在方法抛出异常退出时执行的通知。
后通知(After (finally) advice):
当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
环绕通知(Around Advice):
包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
 
构建环境和前面一样
定义一个接口如下:

java代码:
  1. package cn.javass.Spring3.aop;  
  2. public interface Api {  
  3. public String testAop();  
  4. }  
写一个类实现这个接口

java代码:
  1. public class Impl implements Api{  
  2. public String testAop() {  
  3. System.out.println("test aop");  
  4. return "aop is ok";  
  5. }  
  6. }  
写一个类作为Before的Advice,没有任何特殊要求,就是一个普通类

java代码:
  1. public class MyBefore {  
  2. public void b1(){  
  3. System.out.println("now befoer--------->");  
  4. }  
  5. }  
配置文件,要注意配置的时候要保证一定要有命名空间aop的定义,如下:

java代码:
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4. xmlns:context="http://www.springframework.org/schema/context"  
  5. xmlns:aop="http://www.springframework.org/schema/aop"  
  6. xmlns:tx="http://www.springframework.org/schema/tx"  
  7. xsi:schemaLocation="  
  8. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  9. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd  
  10. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  
  11. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
  12. ">  
  13. <bean id=“testAopApi” class=“cn.javass.spring3.aop.Impl"></bean>  
  14. <bean id=“myBefore” class=“cn.javass.spring3.aop.MyBefore"></bean>  
  15.    
  16. <aop:config>  
  17.   <aop:aspect id="abcd" ref="myBefore">  
  18.     <aop:pointcut id="myPointcut"  
  19.         expression=“execution(* cn.javass.spring3.aop.*.*(..))"/>  
  20.     <aop:before  
  21.        pointcut-ref="myPointcut"  
  22.        method="b1"/>   
  23.   </aop:aspect>  
  24. </aop:config>  
  25. </beans>  
客户端如下:

java代码:
  1. public class Client {  
  2. public static void main(String[] args) {  
  3. ApplicationContext context = new ClassPathXmlApplicationContext(  
  4.         new String[] {"applicationContext.xml"});  
  5. Api api = (Api)context.getBean("testAopApi");  
  6. String s = api.testAop();  
  7. System.out.println("s=="+s);  
  8. }  
  9. }  
  10.    
测试结果如下:
now befoer--------->
test aop
s==aop is ok
原创内容 转自请注明【  http://sishuok.com/forum/blogPost/list/0/2541.html#7308
视频配套PPT,视频地址【  Spring3开发实战-独家视频课程 】

猜你喜欢

转载自jenmhdn.iteye.com/blog/1618693