什么是aop
当前service开发中问题:
每个需要进行事务控制的service代码中事务控制部分代码重复的代码,将这些事务控制重复的代码抽取出来。
解决方法:
采用spring aop面向切面编程对上边的代码进行抽取
AOP( Aspect Oriented Programing) 面向切面编程。Spring1.2 版本开始支持AOP编程 (面向切面编程 )。
采用aop的方法对类代码切面编程,通过横向抽取方法将service中的事务控制的代码抽取出来。
aop的原理
aop面向切面编程的原理就是代理:
1、静态代理
采用一些工具类对原来的类生成一个代理类,代理类以.class存在
2、动态代理(重点,spring基于动态代理实现aop)
在运行中,通过反射生成类的代理对象,在代理对象中对原来的对象进行增强。
spring采用动态代理的技术包括:
1、基于接口生成代理对象
根据接口方法生成代理对象,对原来的代理对象进行增强
使用jdk提供反射实现
2、基于类生成代理对象
根据类生成一个子类(代理对象),在代理对象(子类)中对父类进行增强。
使用CGLib实现
目标:通过运行代理的测试代码了解通过代理对原来对象进行增强的过程!!!
编写原始类:
public interface CustomerServiceAop {
public void insertCustomer(CstCustomer cstCustomer,CstCustomerDetail cstCustomerDetail) ;
}
``
编写代理对象生成代码:
代理对象要对上边的CustomerServiceAop进行增强!!
由于CustomerServiceAop是一个接口,使用jdk提供根据接口生成代理对象:
public class TransactionManagerHandler implements InvocationHandler {
//目标对象,原始对象CustomerServiceAop
private Object target;
//通过构造方法设置目标对象
public TransactionManagerHandler(Object target){
this.target = target;
}
//proxy生成的代理对象
//method目标对象方法的引用
//args目标对象方法调用的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//在方法之前增强,开启事务
System.out.println("开启事务...");
//通过反射调用原始对象的方法
Object obj = method.invoke(target, args);
//在方法之后增强,提交事务
System.out.println("提交事务...");
return obj;
}
如果实现aop,对原始对象生成一个代理对象,在代理对象中添加增强的代码:
1、编写原始类
2、编写增强类 ,包括增强的代码
3、确定目标对象
4、生成代理对象,执行增强类的增强代码,执行原始类中代码
jdk和cglib区别
jdk:基于接口生成代理对象
cglib:基于类生成代理对象
spring底层使用jdk和cglib,如果原始对象实现了一个接口,spring使用jdk,否则 使用cglib生成代理。
AOP联盟
AOP联盟出一套aop的标准。
aop联盟的jar包:
aop术语:
Pointcut(切入点):确定在哪个方法上增强,一个类有多个切点
Advice(通知/增强):在切点上进行增强,包括:前置增强、后置增强、抛出异常增强
Target(目标对象):对目标对象进行增强,生成代理对象
Proxy(代理):对目标对象进行增强,生成代理对象
Weaving(织入):生成代理的时机(过程)
1、动态代理织入,在运行期为目标类生成代理对象
2、编译期织入
Aspect(切面): 包括切点和增强,面向哪个切点进行增强(编程)。
Aop编程入门
- 加入aop相关jar包:
- AOP联盟aopalliance-1.0.jar
Spring aop包 spring-aop-4.2.4.RELEASE.jar
AspectJ 框架jar包 aspectjweaver-1.8.7.jar
Spring 对AspectJ 整合jar包 spring-aspects-4.2.4.RELEASE.jar
AspectJ语法(切点语法)
通过语法配置切入点:
切入点:方法,哪个/此类哪个/些方法
表达式包括两部分:函数名和操作参数。
例子:execution(* com.zking.spring.service.impl..(…)) 匹配com.zking.spring.service.impl包下所有类的所有方法(任意形参),任意返回值。
execution函数名
- com.zking.spring.service.impl..(…)参数
掌握:
execution(* com.zking.spring.service.impl..(…)) 匹配com.zking.spring.service.impl包下所有类的所有方法(任意形参),任意返回值
within(com.zking.service…*) 匹配 com.zking.service包下所有类 (包括子包)所有方法。
增强
AspectJ支持的增强类型:
- Before 前置增强/通知,相当于BeforeAdvice
- AfterReturning 后置增强/通知,相当于AfterReturningAdvice
- Around 环绕增强/通知,相当于MethodInterceptor
- AfterThrowing抛出增强/通知,相当于ThrowAdvice
- After 最终finally增强/通知,不管是否异常,该通知都会执行
伪代码:
public void save(){
try{
//前置增强
调用目标对象方法执行
//后置增强
}catch(Exception ex){
//抛出异常增强
}finally{
//最终finally增强
}
}
如果切点表达 式写错了,不会生成一个代理对象,不会对原始类进行增强了!!!!!
代理对象生成流程:
1、spring要对目标类进行管理(前提!!!)
在容器中配置目标类
2、编写增强类(增强代码)
3、切点,spring根据切点找到目标类中目标方法。
4、生成代理对象(spring自动完成)