1、AOP概念
首先,AOP是对OOP的一个补充。它考虑的是“横切性”问题。横切性问题即可以理解为我们同一层类的问题(例如:Service层)。
它的理念是,把遍历在系统各个角落具有横切性的独立的服务,抽出来放到一个地方,然后等到运行时,再放进去,考虑的是“横向”的东西。将横切性关注的东西给抽出来,会使代码大大减少,更加简洁,更加有复用性。
下图展示AOP中的基本概念:
基础概念不多说,从上图可以看出SpringAOP的实现的过程:
? 找到横切性性关注点(发现横切性问题,具体实现为Advice)
? 编写切入点(Pointcut),即指定Advice的方法的作用域
? 将Advice织入(Weave)目标对象(TargetObject)的Joinpoint
织入(Weave)是动态的,默认采用的方式是JDK的动态代理,当然也可以采用CGLIB代理。
可简单地表示为下图:
2、Spring 对 AOP 的支持—采用Annotation方式
依赖包配置:
*SPRING_HOME/dist/spring.jar
*SPRING_HOME/lib/log4j/log4j-1.2.14.jar
*SPRING_HOME/lib/jakarta-commons/commons-logging.jar
*SPRING_HOME/lib/aspectj/*.jar --(要使用aspectj提供的相关的注解)
源码
interface UserManager
package com.bjpowernode.spring; public interface UserManager { public void addUser(String userName, String password); }
class UserManagerImpl
package com.bjpowernode.spring; public class UserManagerImpl implements UserManager { public void addUser(String username, String password) { System.out.println("---------UserManagerImpl.add()--------"); } }
*class SecurityHandler(将横切性关注点模块化,建立相关的类)
package com.bjpowernode.spring; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class SecurityHandler { /** * 定义Pointcut,Pointcut的名称为addAddMethod(),此方法没有返回值和参数 该方法就是一个标识,不进行调用 */ @Pointcut("execution(* add*(..))") private void addAddMethod() { }; /** * 定义Advice,表示我们的Advice应用到哪些Pointcut订阅的Joinpoint上 */ @Before("addAddMethod()") // @After("addAddMethod()") private void checkSecurity() { System.out.println(""); System.out.println("-------checkSecurity-------"); } }
为所有的方法名中带add的方法,执行之前都加入checkSecurity()服务。
Spring配置文件—ApplicationContext.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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> <!-- 启用AspectJ对Annotation的支持 --> <aop:aspectj-autoproxy/> <bean id="userManager" class="com.bjpowernode.spring.UserManagerImpl"/> <bean id="securityHandler" class="com.bjpowernode.spring.SecurityHandler"/> </beans>
classClient—客户端
package com.bjpowernode.spring; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Client { public static void main(String[] args) { BeanFactory factory = new ClassPathXmlApplicationContext( "applicationContext.xml"); System.out.print(factory); UserManager userManager = (UserManager) factory.getBean("userManager"); userManager.addUser("张三", "123"); } }
运行结果:
-------checkSecurity------- ---------UserManagerImpl.add()--------
3、Spring 对 AOP 的支持—采用"配置文件"方式
与上面实现相同的效果。
* 依赖包配置采用上面的“采用Annotation方式”即可
* 直接看源码:
interface UserManager与上面相同
class UserManagerImpl与上面相同
class SecurityHandler(将横切性关注点模块化,建立相关的类):
package com.bjpowernode.spring; public class SecurityHandler { private void checkSecurity() { System.out.println(""); System.out.println("-------checkSecurity-------"); } }
*Spring配置文件—ApplicationContext.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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> <bean id="userManager" class="com.bjpowernode.spring.UserManagerImpl"/> <bean id="securityHandler" class="com.bjpowernode.spring.SecurityHandler"/> <aop:config> <aop:aspect id = "securityAspect" ref="securityHandler"> <!-- 以Add为开头的方法 <aop:pointcut id="addAddMethod" expression="execution(* add*(..))"/> --> <!-- com.bjpowernode.spring包下所有类的所有方法 <aop:pointcut id="addAddMethod" expression="execution(* com.bjpowernode.spring.*.*(..))"/> --> <!-- com.bjpowernode.spring包下所有类的所有add与del方法 --> <aop:pointcut id="addAddMethod" expression="execution(* com.bjpowernode.spring.*.add*(..))||execution(* com.bjpowernode.spring.*.del*(..))"/> <!-- Advice,配一个Pointcut --> <aop:before method="checkSecurity" pointcut-ref="addAddMethod"/> </aop:aspect> </aop:config> </beans>
主要是在aspect节中,将Advice与Poincut联系起来
classClient—客户端也与上面相同
运行结果正确:
-------checkSecurity------- ---------UserManagerImpl.add()--------
4、总结
做AOP,重点是,发现Aspect(切面),并在“运行时”切入进去。织入过程,默认采用JDK的动态代理。动态灵活,但比较慢;静态比较快(可以预编译),但不灵活。Spring的AOP可以针对pojo对象提供声明式服务,如声明式事务; Ejb里面的SessionBean也可以提供声明式事务。