文章目录
P63动态代理
P64 专有名词
P66 AOP的使用步骤
导包:
AOP 细节1:IOC容器中保留的是组件的代理对象
为Calculator接口的实现类加上AOP,从IOC容器中获取要用其接口类型。或者用id,也就是类名小写来获取。
原因:
该对象加入到了IOC容器中,IOC容器启动时创建的是其代理对象
代理对象和该对象共同点:实现了相同的接口
该接口虽然未加入IOC容器中,但在容器中获得该接口类型的(ioc.getBean(Capculator.class)),而其实现类已经加入到IOC 容器中。
当有切面类加入IOC容器中时,创建的是代理对象。
AOP 细节1(补充):cglib为没有实现接口的组件创建对象
如果按照上面的那样,就需要创建很多的接口。这是很麻烦的!
现在不去实现接口,使用Spirng,会为其创建代理对象。(上面是JdK为其创建代理对象)
总结:
- 实现了接口,就用JdK创建代理对象。
- 没有实现接口,Spring创建代理对象。
AOP 细节2:切入点表达式(通配符)
AOP 细节2:通知方法执行顺序
AOP 细节3:获取目标方法的信息
@AfterReturning(value = "execution(public int com.liuc.impl.MyCaculate.*(..))",returning = "result")
public static void logReturn(JoinPoint joinPoint,Object result){
// System.out.println("["+method.getName()+"]方法返回,参数列表:"+ Arrays.asList(args));
System.out.println("["+joinPoint.getSignature()+"]方法返回,返回结果:"+result);
}
@AfterThrowing(value = "execution(public int com.liuc.impl.MyCaculate.*(..))",throwing = "e")
public static void logError(JoinPoint joinPoint,Exception e){
// System.out.println("["+method.getName()+"]方法结束");
System.out.println("["+joinPoint.getSignature()+"]方法异常,异常信息是:"+e);
}
抽取切入点表达式
// 抽取切入点表达式
@Pointcut("execution(public int com.liuc.impl.MyCaculate.*(..))")
public void myPointCut(){};
@Before("myPointCut()")
public static void logStart(JoinPoint joinPoint){
// System.out.println("["+method.getName()+"]方法开始,参数列表:"+ Arrays.asList(args));
System.out.println("["+joinPoint.getSignature()+"]方法结束,参数列表:["+joinPoint.getArgs()+"]");
}
@AfterReturning(value = "myPointCut()",returning = "result")
public static void logReturn(JoinPoint joinPoint,Object result){
// System.out.println("["+method.getName()+"]方法返回,参数列表:"+ Arrays.asList(args));
System.out.println("["+joinPoint.getSignature()+"]方法返回,返回结果:"+result);
修改一处就可以了,不用到处修改
AOP细节4:环绕通知
没有环绕时:普通前置—>目标方法—>普通后置—>普通返回/异常
环绕前置—> 普通前置—> 目标方法执行 —>环绕返回\异常—> 环绕后置 —>普通后置—> 普通返回\异常
注: 目标方法在环绕通知方法中执行,所以环绕优先执行,普通的在后面
- 环绕通知类似动态代理的功能,执行目标方法(可以修改参数、返回值)会影响目标方法;
- 普通的通知方法不会影响目标方法,只是在执行目标方法前后会调用,如果不希望改变目标方法,就选择普通的通知方法
AOP细节5:多个切面类执行属性
谁在前,谁在后,通过切面类的首字母顺序 或者使用注解@Order(值),这个值越小越好
在LogUtils中添加环绕通知后,整个的执行顺序:
LogUtils中加的环绕只针对与LogUtils这一层,VaApsect则不受影响。因此执行完目标方法后,显示执行VaAspect的后置和返回,接着再执行LogUtils的环绕。
AOP注解的步骤
基于配置的AOP
前置的顺序不用关心
例子: