一、AOP相关概念及原理
1、发展过程
假设对于一个存在的类Student,对其进行功能扩展:
- 传统方式:直接在源码中修改;麻烦易错,不好维护
- 纵向抽取机制扩展:如写一个扩展类,在该类中写扩展方法,让Student基础该类,调用该类的扩展方法;耦合度仍然过高,当父类改变时,仍需要调整Student中的调用形式(如方法名改变、参数改变等)
- 横向抽取机制扩展:及面向切面的思想(AOP),采用动态代理的原理实现。
- 情况一:Studnent实现了某个接口,创建一个与Student**同级**的实现该接口的代理对象进行扩展,及JDK动态代理
- 情况二:Student没有实现接口,则创建Student子类的代理对象,在子类中调用super(父类)中的方法,完成加强,即cglib动态代理
2、相关概念
- 连接点(JoinPoint):可被增强的方法
- 切入点(PointCut):实际增强的方法
通知/增强(Advice):实际增强的功能
- 前置通知:在方法之前增强
- 后置通知:在方法之后增强
- 异常通知:方法出现异常后增强
- 最终通知:在后置之后通知
- 环绕通知:增强的方法要加(ProceedingJoinPoint pjp)形参,调用pjp.proceed();即调用带增强的方法
切面:把增强应用到切入点的过程
二、Spring与Aspectj进行AOP操作(xml配置方式)
1、引入aop的jar包 aopalliance、aspectjweaver、spring-aop、spring-aspects
2、加约束
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
</Beans>
3、创建Student类及切入点的类StudentAdd
public class Student {public void Show() {System.out.println("原始:我是一个小学生...");}
}
public class StudentAdd {//前置增强public void ShowBefore() {System.out.println("前置:我的名字叫小明...");}//后置增强public void ShowAfter() {System.out.println("后置:我上二年级....");}//最终增强public void ShowFinal() {System.out.println("最终:我要好好学习...");}//环绕增强public void ShowAro(ProceedingJoinPoint pj) throws Throwable {System.out.println("前环绕:============");pj.proceed(); //执行方法System.out.println("后环绕:************");}
}
4、Aspectj配置AOP操作
<!-- 扫描包下的所有注解 --><context:component-scan base-package="com.aoptest"></context:component-scan><!-- 配置对象的创建 --><bean id="student" class="com.aoptest.test1.Student"></bean><bean id="add" class="com.aoptest.test1.StudentAdd"></bean><!-- aop配置 --><aop:config><!-- 配置切入点(那些方法要增强) --><aop:pointcut expression="execution(* com.aoptest.test1.Student.Show(..))" id="show"/><!-- 切面配置(将增强应用到上面的方法) --><aop:aspect ref="add"><aop:before method="ShowBefore" pointcut-ref="show"/> <!-- 前置通知 --><aop:after method="ShowFinal" pointcut-ref="show"/> <!-- 最终通知 --><aop:after-returning method="ShowAfter" pointcut-ref="show"/> <!-- 后置通知 --><aop:around method="ShowAro" pointcut-ref="show"/> <!-- 环绕通知 --></aop:aspect></aop:config>
5、附:配置中的expression属性
<aop:pointcut expression="execution(* com.aoptest.test1.Student.Show(..))" id="show"/>
- execution(* com.aoptest.test1.Student.Show(..)) //*代表方法类型为任意(public private等),(..)代表所有参数
- execution(* com.aoptest.test1.Student.*(..)) //Student类中的所有方法
- execution(* .(..)) //项目的所有方法
- execution(* get*(..)) //以get开头的方法
二、Spring与Aspectj进行AOP操作(注解方式)
1、创建对象,仍使用上面的Student和StudentAdd类
2、Spring中配置开启AOP操作
<!-- 扫描包下的所有注解 --><context:component-scan base-package="com.aoptest"></context:component-scan><!-- 配置对象的创建 --><bean id="student" class="com.aoptest.test2.Student"></bean><bean id="add" class="com.aoptest.test2.StudentAdd"></bean><!-- aop注解方式 开启aop操作 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
3、在”增强类”上使用注解
@Aspect
public class StudentAdd {//前置增强@Before(value = "execution(* com.aoptest.test2.Student.Show(..))")public void ShowBefore() {System.out.println("前置:我的名字叫小明...");}
}