今天一看,Blog爬到了第一,又很久没更新了,因此就把这两天正在写的电子书的一部分贴上吧。今天想找找Spring 2.0 AOP的例子,谁料想网上文章一大抄,而且呢,大部分人是直接copy Spring的文档,自己连个demo也不写一种的那个,就见一堆文章说的云里雾里热火朝天的AOP,也没见着几个能跑的例子。最后总算找到了个兄弟的小短文,有个能跑的例子,这才算弄好了1.2和2.0的对比部分。好了,下面是正文(其实尚未完工,先凑合看吧):
10.3 开发Spring 1.2 AOP应用
本节将会给大家展示一个恐怖的例子,FBI特务人员已经介入了您的生活,您所做的一切都在他们的监视之中,包括聊QQ,泡MM,这在现实生活中是真实存在的,为了民众的安全和稳定,对嫌疑犯进行必要的监控是必要的。
注意:本章虽然介绍了多种AOP实现方式,然而,在实际项目中只要使用一种就可以达到目的了(因为Spring的AOP存在多种写法,完全掌握还是挺复杂),其它方式仅供参考,千万不要像孔乙己一样,研究“茴”字的N种写法,这样就脱离了学习技术的初衷了:学习是为了解决问题,不是为了炫耀自己。另外,如果在项目中滥用AOP的后果就是系统的执行效率大大降低,甚至配置不当会导致死循环。记住一个真理:系统越复杂,效率越低,出故障的可能越大。另外一条建议:千万不要用AOP在服务器上记录日志,或者在服务器上打印不必要的调试信息,那样对系统只能有害无益,日志输出是单线程操作,切记。做项目,一般来说是功能越少越好。高手更多的时候只能做出破坏力大,不易维护的垃圾系统。
10.3.1 开发Man对象
这个项目非常简单,仿照上节内容,创建项目并添加Spring开发功能,不同的是添加library的时候要把Spring 2.0 AOP Libraries加入进来。因为Spring 2.0的类库是兼容1.2的,所以这里就用2.0了。项目名为Spring1_2AOP。接下来我们要创建一个自由人的对象,他有聊QQ和泡MM这两个方法,还有一个姓名属性。好了,先建立这个类:
| /** * 具有聊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"); } } |
清单10.6 Man类源码
10.3.2 开发前置通知(Before advice)对象:FBI
首先贴一段Spring文档中关于Before advice的介绍:
前置通知(Before advice): 在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
说通俗点就是写一个如何处理监视结果的对象,可以把监视结果打印出来以作为必要的时候的呈堂证物,或者派探员立即跟踪,但是这个过程只能在你进行某活动前进行,否则就失去监视的意义了,这个对象更像“诸葛亮”。详细的了解这个类需要学习JDK里面关于反射部分的内容,下面是这个类的代码:
| import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; /** * 联邦调查局的探员将您的所有行动都记录在案。 * @author BeanSoft */ public class FBI implements MethodBeforeAdvice { public void before(Method method, Object[] args, Object target) throws Throwable { Man man = (Man)target; System.err.println("FBI 发现" + man.getName() + "正在进行 " + method.getName() + " 活动。"); } } |
清单10.7 FBI类源码
10.3.3 装配拦截器和Bean
最后要做的,就是创建一个平民对象,注意不是自由人哦,因为平民是随时处于FBI的监视之下的。这个对象本质上是类ProxyFactoryBean的一个示例,这个类位于包org.springframework.aop.framework下,自由人只能活在这个代理工厂类的阴影下了,也就是成了平民了。好了,我们把相应的Spring配置文件代码放给大家:
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="man" class="Man"> <property name="name"> <value type="java.lang.String">张三</value> </property> </bean> <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> </beans> |
清单10.8 Spring AOP 配置文件源码 applicationContext.xml
在这个文件中,定义了两个bean:man和fbi,都是普通的类定义。复杂一些的地方在civilian这个bean的定义中,它要拦截或者监视的目标(target)是man,负责进行处理监视结果的对象(interceptorNames)是fbi,具体进行监视工作的对象,就是这个ProxyFactoryBean,它相当于窃听器之类的东西,但是很显然窃听结果是需要人来处理的,那就是FBI。
简单说: man成为了civilian,它被ProxyFactoryBean监控,监控结果交给FBI处理。很显然,如果没有国家,也就没有civilian,更谈不上FBI了。所以,在这里您不能再去找man,因为man在实际生活中是不存在的,所以您只能找civilian,这样您才能感觉到FBI的存在。下面是相关的bean关系图:

图 10.9 Bean关系图
10.3.4 测试和运行
OK,如上节讨论,只有当平民的时候才会被监视,现在我们就可以写一个测试类来感受一下平民生活:
| import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AOPTest { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); Man man = (Man) ctx.getBean("civilian"); man.qq(); man.mm(); } } |
清单10.9 Spring AOP 测试类源码
运行一下,您就可以看到可怕的真相:
| log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext). log4j:WARN Please initialize the log4j system properly. FBI 发现张三正在进行 qq 活动。 FBI 发现张三正在进行 mm 活动。 我在聊QQ 我在泡MM |
是不是很恐怖呢?FBI正在监控您的一举一动,并把这些东西都记录在案。现在你应该可以了解AOP的过程了:调用man这个bean的任何一个方法之前,都会事先通知(调用)fbi这个bean并告知相关的调用信息,这些信息包括方法(method),参数(args)以及目标对象(target,这里就是man这个对象)。
如果你把上面的代码改成ctx.getBean(“man”),那么自由人是不会被监控的,所以这时候您就不会看到FBI输出的恐怖信息了。此时的输出如下:
| log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext). log4j:WARN Please initialize the log4j system properly. 我在聊QQ 我在泡MM |
10.3.5 AOP简介和相关概念
现在我们已经写了一个很简单的Spring AOP 例子,现在就给大家简单介绍一下相关的概念,这些信息来自于Spring的中文文档。
面向切面编程(AOP)提供另外一种角度来思考程序结构,通过这种方式弥补了面向对象编程(OOP)的不足。 除了类(classes)以外,AOP提供了 切面。切面对关注点进行模块化,例如横切多个类型和对象的事务管理。 (这些关注点术语通常称作 横切(crosscutting) 关注点。)
我们来定义一些重要的AOP概念。这些术语不是Spring特有的。 不幸的是,Spring术语并不是特别的直观;如果Spring使用自己的术语,将会变得更加令人困惑。
l 切面(Aspect): 一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @Aspect注解(@AspectJ风格)来实现。
l 连接点(Joinpoint): 在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。 在Spring AOP中,一个连接点 总是