spring开发aop应用有三种方法: 一:Spring 1.2版本中通过ProxyFactoryBean来实现aop,即通过动态代理来实现的,Aspect必须继承MethodBeforeAdvice,MethodAfterAdvice等 <!--被代理的对象--> <bean id="man" class="Man"> <property name="name"> <value type="java.lang.String">张三</value> </property> </bean> <!--继承了MethodBeforeAdvice类的 Aspect-> <bean id="fbi" class="FBI" /> <bean id="civilian" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <ref bean="man" /> </property> <property name="interceptorNames"> <list> <value>fbi</value> </list> </property> </bean> 二:Spring 2.0 AOP 应用 需要改的是FBI 这个类,而且它也不需要再实现某些接口了 public class FBI { public void before(JoinPoint point){ Man man = (Man)point.getTarget(); System.err.println("FBI 发现" + man.getName() + "正在进行 " + point.getSignature().getName() + " 活动。"); } } 注意这个类里面的方法 before(JoinPoint),方法名可以是任意的,可以带一个JoinPoint 类 型的参数,也可以不带参数直接写成before(),但是这个连接点(JoinPoint)对象带来了所 有和这次方法调用有关的信息,包括方法参数,目标对象等等,所以一般要做日志记录的话 会带上它。 接下来是测试类的代码,和以前的几乎没有任何不同,只不过现在直接访问的是man 这个bean。 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <bean id="fbi" class="FBI" /> <bean id="man" class="Man"> <property name="name"> <value type="java.lang.String">张三</value> </property> </bean> <aop:config> <aop:pointcut id="manPointcut" expression="execution(* Man.*(..))" /> <aop:aspect id="beforeExample" ref="fbi"> <aop:before pointcut-ref="manPointcut" method="before" /> </aop:aspect> </aop:config> </beans> 1. 配置文件的开头加入了aop 命名空间,如代码中粗斜体所示。 2. 使用aop:config 标签来定义AOP,不是使用ProxyFactoryBean 来定义一个新的 bean。 一个是人的对象,另 一个则是联邦调查局的探员。而aop:config 中定义了所有的AOP 设置信息。aop:pointcut 定义了一个切入点,id 给出了这个切入点的唯一名字,而expression 定义了切入点的表达 式,那么这个定义到底表示了什么信息呢?它的意思是表示一种场景,即执行(execution) Man 对象的所有方法的这种情况,这就是表达式execution(* Man.*(..))的意义所在, Man.*(..)表示Man 类的所有方法。接下来呢,需要定义一个切面,用aop:aspect 来定义, 它的ref 属性指定了这个切面所对应的bean 定义的id,这里指向fbi 这个bean 类;子标签 aop:before 则指示了当发生了名为manPointcut 的切入点(情况)前(用pointcut-ref 属性 指定,pointcut-ref=”manPointcut”),就调用名为before 的方法,这个方法位于aspect 里 面的引用的那个bean 中,这里是fbi(即ref=”fbi”)。其实Spring 执行到这里后,会自动的 把这些代码翻译成底层的Bean 定义(后台依然会采用ProxyFactoryBean 这样的机制), 然后把对应的获取bean 的操作直接委托给代理类,这就是为什么上文提到的测试类只需要 访问原来的man 这个bean,对应的拦截类就会被执行的原因。从这里看到Spring 2.0 中要 定义一个AOP 的bean 类,仍然是比较复杂的,XML 文件和概念都增加了很多,需要读者 慢慢来学习和理解。 三使用标注(@AspectJ)实现AOP 的一个库来做切点(pointcut)解析和匹配。 为了在Spring 配置中使用@AspectJ aspects,你必须首先启用Spring 对基于@AspectJ aspects 的配置支持,自动代理(autoproxying)基于通知是否来自这些切面。 自动代理是 指Spring 会判断一个bean 是否使用了一个或多个切面通知,并据此自动生成相应的代理 以拦截其方法调用,并且确认通知是否如期进行。 通过在你的Spring 的配置文件中引入下列元素来启用Spring 对@AspectJ 的支持: <aop:aspectj-autoproxy/> 也可以通过在你的application context 中添加如下定义来启用@AspectJ 支持: <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyC reator" /> 你需要在你的应用程序的classpath 中引入两个AspectJ 库:aspectjweaver.jar 和 aspectjrt.jar。我们这里用的MyEclipse,在添加Spring 开发功能时已经自动的加入了这些 类库文件,无需手工配置了。 定义切面Aspect:在启用@AspectJ 支持的情况下,在application context 中定义的任意带有一个@Aspect 切面(拥有@Aspect 标注)的bean 都将被Spring 自动识别并用于 配置在Spring AOP。 定义切入点Pointcut:现在通过在 @AspectJ 标注风格的 AOP 中,一个切入点签名 通过一个普通的方法定义来提供,并且切入点表达式使用 @Pointcut 标注来表示(作为切 入点签名的方法必须返回 void 类型)。代码可以参考清单10.12。 好了,引用了这么些文档,我们需要介绍这个基于标注的新的AOP项目了,这个项目 的名字是Spring2_0AOPAspectJ,如前一节所示加入了Spring核心和AOP类库后,就可以 开发了。那么相比较10.4.1 使用aop 标签实现AOP一节,这一个项目的代码仅仅有两个地 方要改。首先我们要修改FBI类的源码,加入标注来实现切面和切入点定义,如下所示: import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; /** * 联邦调查局的探员将您的所有行动都记录在案。 * @author BeanSoft */ @Aspect public class FBI { @Before("execution(* Man.*(..))") public void before(JoinPoint point){ Man man = (Man)point.getTarget(); System.err.println("FBI 发现" + man.getName() + "正在进行 " + point.getSignature().getName() + " 活动。"); } } 清单10.12 加入了Aspect 标注的FBI 类 这个类中的@Before 后面的"execution(* Man.*(..))"是切入点所对应的切入点点表达式,其意 义和上一节的是一致的,仍然表示的是执行 Man 类的所有方法时将触发此方法的执行。 使用了这种写法后,XML 配置文件将大大简化,其内容如下所示: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <aop:aspectj-autoproxy/><bean id="fbi" class="FBI" /> <bean id="man" class="Man"> <property name="name"> <value type="java.lang.String">张三</value> </property> </bean> </beans> 1. 加入了粗斜体的<aop:aspectj-autoproxy/>定义; 2. 去掉了<aop:config>标签部分。 可以看到使用这种方式后,AOP 的开发和配置变的极其简单。这就是JDK 1.5 引入标注开 发后带来的好处。当然弱点嘛,那就是要修改配置必须重新编译源代码了。 注意:在这里你不能去掉<bean id="fbi" class="FBI" />这一个bean的定义,否 则自动AOP代理对象就没有机会被创建并工作了,那样的话man对象被代理也就无从谈起 了。 四开发环绕通知(Around Advice)AOP 应用 @Aspect public class FBI { @Around("execution(* Man.*(..))") public Object before(ProceedingJoinPoint point) throws Throwable { Man man = (Man)point.getTarget(); System.err.println("FBI 发现" + man.getName() + "即将正在进行 " + point.getSignature().getName() + " 活动。"); // 禁止张三泡MM if(point.getSignature().getName().equals("mm")) { System.err.println("FBI 将阻止 " + man.getName() + " 泡MM。"); } else if(point.getSignature().getName().equals("sayHelp")) { System.err.println("FBI 将欺骗 " + man.getName() + " 的朋友告 诉他们他很好。"); return "我是 " + man.getName() + " ,我现在过的很好。"; } else {Object object = point.proceed(); System.err.println("FBI 发现" + man.getName() + "已经完成了 " + point.getSignature().getName() + " 活动。"); return object; } return null; } } 现在张三不光是不能泡MM 了,当他求救的时候,FBI 还可以直接拦截并修改,将其请求的 信息“救我,我是张三!”改成“我是张三,我现在过的很好。”,这样通过欺骗行为,张三 的朋友永远也不知道发生了什么事。 /** * 具有聊QQ和泡MM以及求救三个行为的人对象,还有一个用户名属性。 * @author BeanSoft */ public class Man { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void qq() { System.out.println("我在聊QQ"); } public void mm() { System.out.println("我在泡MM"); } public String sayHelp() { return "救我,我是" + getName(); } }