AOP的概念不好解释, 有一大堆的术语都很拗口,还是先看一个代码例子,在src根目录下面新建一个package叫做aop,把这个单元所有的代码都放在这个包里面,有一个接口BookService,它有一个实现BookServiceImpl, 专门来处理与Book相关的业务逻辑。
你不需要把BookServiceImpl 这个例子拷贝出来并且测试,上面的TransactionManager和PerformanceMonitor 都是假设的类,只需要阅读一下就可以了。 removeBook 和 insertBook 调用dao层来和数据库交互,同时我们给这两个方法加上了性能监测和事务控制。而性能检测和事务控制很多时候都是必需的。而且他们紧紧地依附于业务逻辑,monitor.start();txmanager.begin(); 以及txmanager.commit();monitor.end();这些和主流业务逻辑无关的代码无法通过其他方式消除。
AOP的目的就是要把这种和核心逻辑无关的却又无法消除的代码从核心代码中剥离出来,使业务逻辑类专注于业务逻辑, 并且在适当的时候(比如运行时)再把他们植入到核心业务代码中.说白了,就是希望把上面的BookServiceImpl变成这个样子:
那么性能检测和事务控制的代码跑到哪里去了呢? 到增强(Advice)里面去了. 下面看几个概念,包括Advice.
连接点(Joinpoint): 程序执行的某个特定位置, 比如方法调用前后, 类初始化前,异常抛出之后.
增强(Advice): 植入到目标类的连接点上的程序代码.
目标对象(Target): 被植入增强的类, 比如上面简化之后的BookService.
代理(Proxy): 被植入增强之后产生的结果类.
我们把性能监测和事务控制的逻辑除掉之后,如果想继续使用性能检测和事务控制, 则要做两件事情:
1 创建增强(Advice),把性能监测和事务控制的代码放到增强里面;
2 用一种灵活的方式把增强(Advice)植入到干净的BookService里面.
Spring提供了前置增强,环绕增强,后置增强,异常抛出增强等,
前置增强 假如我们的业务逻辑类就是上面的BookServiceImpl,它是一个干净的业务逻辑,我们利用前置增强来改善一下它的方法,希望在方法调用前做一些工作. 创建一个前置增强,继承自MethodBeforeAdvice.他的作用很简单, 就是打印出目标对象的方法名. 需要注意的是aopalliance.jar, cglib, spring-aop.jar要加入进来。
通过代理工厂ProxyFactory把Advice植入到目标对象BookService并且产生代理对象.
打印出的消息:
advice before method aop.BookService.insertBook().
book inserted.
advice before method aop.BookService.removeBook().
book removed.
说明在方法调用前,增强代码被执行了.
后置增强(AfterReturningAdvice) 目标方法调用之后执行.
稍微修改一下TestAdvice,为service添加一个后置增强。
打印的消息:
advice before method aop.BookService.insertBook().
book inserted.
method aop.BookService.insertBook() has been executed.
advice before method aop.BookService.removeBook().
book removed.
method aop.BookService.removeBook() has been executed.
环绕增强(MethodInterceptor) 就是在方法前后都有代码段执行。
再次修改TestAdvice,把以前的两个Advice注释掉,单独使用Interceptor看效果。
打印出的消息:
the method aop.BookService.insertBook() will be executed.
book inserted.
the method aop.BookService.insertBook() has been executed.
the method aop.BookService.removeBook() will be executed.
book removed.
the method aop.BookService.removeBook() has been executed.
还有异常抛出增强我就不给例子了,它继承自ThrowsAdvice,在方法抛出异常的时候来增强方法。
在Bean config中配置和使用AOP 因为Spring有强大的IOC容器, 所以通过配置来体现AOP才是Spring推荐的。配置中要配置增强(Advice),目标Bean(Target),代理Bean;
然后写一个测试类,看看能不能和编程式的一样可以正常工作。
一切工作正常。
切面 在前面讨论的增强中,他们作用于target的方法上,根据实现的接口的不同,可以作用于方法前,方法后,环绕,抛出异常之后,而且这些增强作用于该类的所有方法,也就是说增强不能定位到具体的方法,但有的时候我们只希望某些方法得到增强,比如我有一个BookService,他有insertBook,insertBookCategory,insertPublisher,getAll, findById, findByName等方法,但是我只希望以insert,update,delete开头的方法开启事务,那就需要用到切面。 切面和增强不同的是,他包含增强,还包括一个方法匹配器。切面有动态切面和静态切面,我演示一下静态正则表达式方法匹配切面的用法, 因为这个在后面Spring事务管理的时候你会发现他们有多么相似。先配置一个正则表达式切面:
通过这个配置应该看出,切面除了包含Advice,还有方法匹配的信息。 修改一下先前配置的bookService的代理对象
测试:
关于AOP还有引介(Introduction),动态切面, 复合切面,基于AspectJ的AOP,因为项目中我没有使用到过,所以不打算介绍。Aop用的最多的地方也就是事务管理中为需要开启事务的service配置代理对象。
代理底层使用了cglib技术,或Jdk自带的代理,但是jdk自带的代理只能对接口代理,如果有兴趣,可以用jdk的代理写几个例子看看。有一点要说的是,凡是用到代理的地方,性能都会大打折扣。
下一讲将学习spring对dao的支持。