代理模式-->EnableAspectJAutoProxy源码解析-->项目日志切面
2020-08-31 16:37:17 0 举报
spring-Aop
作者其他创作
大纲/内容
//获取aop的动态通知的拦截器Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
通过自定义的handler来创建目标类的代理对象
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
后置处理器如何解析增强通知?
切点函数4pointCutForClass
最终方法结果
java.lang.reflect.Proxy.ProxyClassFactory#apply
JdkDynamicAopProxy
ProxyFactory proxyFactory = new ProxyFactory();//将AbstractAutoProxyCreator属性复制到代理工厂proxyFactory.copyFrom(this);
@Around通知
如果都不满足
内部使用this调用
Callback[] callbacks = getCallbacks(rootClass);
获取callback
true
org.springframework.aop.framework.JdkDynamicAopProxy#invoke
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
原因见下方红色标注
copyFrom(ProxyConfig other)
用代理工厂创建代理对象
满足任意条件
getAopProxyFactory().createAopProxy(this);
确定代理方式
通过类继承代理
public class UserServiceProxy implements UserService { private UserService userService; public UserServiceProxy(final UserService userService) { this.userService = userService; } @Override public void login() { Long start = System.currentTimeMillis(); userService.login(); log.info(\"调用时间:\" +(System.currentTimeMillis()-start)); }}
ture
//frozen冻结配置后,将无法更改通知。默认为false proxyFactory.setFrozen(this.freezeProxy);
如果是配置类
切点表达式2针对mq入口@Pointcut(\"execution(public * com.mq.consum.MessageActivityListener.consume(..))\")
比如AfterReturningAdviceInterceptor
总结
Cglib动态代理
项目切面日志
获取所有通知
同样最终也是由MethodInvocation 完成
OOP-->AOP面向对象编程-->面向切面编程Object Oriented Programming-->Aspect Oriented Programming
获取实例化前的后置处理器放到缓存中的bean
判断接口是合理的代理接口,同时不是GroovyObject,,这样的内部语言接口,同时接口有至少一个方法
return retVal;
accountService.updateAccount(\"fox\
创建代理工厂
使用accountService重新调用
Advisor是处理通知的基础接口。
核心方法
retVal = invocation.proceed();
还可以使用((AccountService) AopContext.currentProxy())
//最终创建代理对象return proxyFactory.getProxy(getProxyClassLoader());
AbstractAutoProxyCreator
已目标接口的实现类作为属性创建Cglib代理类,先创建代理对象,再执行目标方法,执行方法时会被intercept方法进行增强
切点函数1pointCutForControllerRemove
静态代理
在bean实例化前调用后置处理器:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
实例化后的后置处理器
修饰方法不是public修饰的
enhancer.create
oriented [ˈɔːrientɪd]朝向; 面对; 确定方向
CglibAopProxy
((AccountService) AopContext.currentProxy()).queryAccount(\"fox\
首先去获取Adive,获取到通知才会去创建代理对象。
移除缓存中的bean,如果成功了
通过实现接口完成代理
1
设置ProxyTargetClass(true);
将通知和目标源赋值给动态代理工厂
直接有JdkDynamicAopProxy的方法完成
proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource);
获取所有合格的Advisors来代理这个类对应的TargetSource
java.lang.reflect.Proxy#newProxyInstance
如果Modifier.isPublic(method.getModifiers()为false,则返回的结果为null,不进行代理
aopProxyFactory.createAopProxy(AdvisedSupport config)
//设置构建前不拦截 enhancer.setInterceptDuringConstruction(false); //设置callbackenhancer.setCallbacks(callbacks);
this.proxyTargetClass = other.proxyTargetClass; this.optimize = other.optimize; this.exposeProxy = other.exposeProxy; this.frozen = other.frozen; this.opaque = other.opaque;
可以通过调用代理生成器ProxyGenerator的另一个generateProxyClass方法,来获取byte流,输出成文件
2
proceed
ProxyTargetClass
@AfterReturning通知
基于aspectJ:@EnableAspectJAutoProxy
继承于Proxy实现目标接口完成代理
判断beanFactory是否是preserveTargetClass
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { //是否优化isOptimize默认false if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { //如果是CGlib的这里拿到的就是接口的实现类。 Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException(\"。。.\"); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { //目标类是接口,或者代理类是继承Proxy实现代理的 return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else {//@EnableAspectJAutoProxy设置为false return new JdkDynamicAopProxy(config); }
UserService userServiceImpl = new UserServiceImpl();CglibProxy cglibProxy = new CglibProxy(userServiceImpl);UserService proxy = (UserService) cglibProxy.getProxyInstance();proxy.login();
创建对应的代理类
在AccountServiceImpl中重新注入AccountService
切点表达式1针对controller@Pointcut(\"execution(public * com.sgcc.controller.*.*(..))\")
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept
通过spring框架内部的自动代理工具AutoProxyUtils,对指定的bean进行判断
this是当前对象,不是代理对象,所以不会走代理逻辑。
切入点表达式:官网介绍 https://docs.spring.io/spring/docs/5.2.7.BUILD-SNAPSHOT/spring-framework-reference/core.html#aop-pointcuts-examples@Pointcut(execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?))modifiers-pattern? 代表方法修饰符比如public。ret-type-pattern:方法返回类型 declaring-type-pattern? :全限定类名 name-pattern:方法名 param-pattern :参数名 throws-pattern? :抛异常的类型 ?代表可以不写eg:execution(* com.xyz.service..*.*(..))还有一些其他不常用的:within只能精细到类,而execution可以精确到方法名。args(类型):指定拦截的方法参数类型 this(指定目标类的类型)一些特殊的:@Pointcut(\"bean(foxDao)\") 指定bean@annotation(自定义注解的路径) 会对被指定的注解修饰的类进行增强。比如@TranSational@target(被切的注解路径) 比如@Pointcut(\"@target(org.springframework.stereotype.Service)\") 被@service修饰的都会被增强@within也是只能精确到类,被指定注释修饰的类才会被增强@args也是只能指定参数类型通知的执行顺序:环绕通知--》前置before通知--》代码逻辑--》环绕通知--》后置after通知--》afterReturn通知通知使用注意事项:每个通知只能指定一个其切点表达式,如果需要多个切点,可以写多个通知。
父类
切点表达式3针对方法注解@Pointcut(\"@annotation(com.utils.annotation.InvokeLogMethod)\")
自定义注解(针对自定义注解修饰的部分进行切面增强)
最终生成的文件
通过CglibMethodInvocation对方法进行动态调用,执行通知的内容
org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
业务调用的核心
@Import(AspectJAutoProxyRegistrar.class)public @interface EnableAspectJAutoProxy {
Spring为何要加进来jdk的aspectJ技术:Spring自带的增强只能在运行时,通过反射对指定对象增强。而aspectJ还可以在编译过程中或者加载过程中进行增强。比如通过特殊的编译器在编译过程中对字节码进行操作增强。在类加载时,通过jdk中的agent,,写一个promain方法在main方法执行前通过instrumentation接口的addtransformer传进来一个transformer,它会使用字节码插装的方式进行增强。org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation:在源码中,进行创建实例前后置处理器调用的方法里,️先解析通知即实现advisor接口的bean和通知的相关注解(before,after,around等),advisor接口实现类比如事务的TransactionAttributeSourceAdvisor就会走这里。️会通过beanclass和beanname来获取对应的targetsource,判断是否为null,如果不为null,就会进行Spring的增强,在bean实例化之前生成代理对象,为null就返回了。我们如果使用targetsource修饰该类,就是在这里进行增强的。
org.aopalliance.intercept.MethodInterceptor#invoke
切点函数2pointCutForMqRemove
通过Enhancer字节码技术将目标类作为父类进行增强完成代理
@AfterThrowing通知
jdk动态代理
当执行接口的方法执行时,就会被拦截器拦截
事务失效场景源码解析
false
根据beanclass和beanName将对应的beanDefinition封装到TargetSource
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
非public修饰的方法事务失效的原因
ObjenesisCglibAopProxy
测试方法
boolean retVal = Advice.class.isAssignableFrom(beanClass) ||\t\t\t\tPointcut.class.isAssignableFrom(beanClass) ||\t\t\t\tAdvisor.class.isAssignableFrom(beanClass) ||\t\t\t\tAopInfrastructureBean.class.isAssignableFrom(beanClass);
getProxy(classLoader);
自定义一个代理器实现InvocationHandler接口,对invoke方法进行重写增强
isInfrastructureClass(beanClass)
从缓存中获取所有的通知,并解析
org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#proceed
写一个代理类实现目标类接口,在内部对需要增强的方法进行重写增强。也可以将目标类接口作为属性注入,只写增强部分,原方法由目标类执行
简述代理模式
createAopProxy().getProxy(classLoader);
最终执行代码
this.methodProxy = (Modifier.isPublic(method.getModifiers()) && method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) && !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ? methodProxy : null);
指定bean的beanFactory的属性为originalTargetClass
获取targetSource
创建CglibMethodInvocation
createAopProxy()获取AopProxy
特定(用于释放threadlocal变量)
Enhancer enhancer = createEnhancer();
public final class LiJieProxy extends Proxy implements TestService {
后置通知
该接口方法会根据不同的通知来由不同的实现类完成
核心实现
不是配置类
设置父类和callback属性enhancer.setSuperclass(proxySuperClass);enhancer.setCallbackFilter(new ProxyCallbackFilter( ...)); enhancer.setCallbackTypes(types);
切点表达式3针对类注解@Pointcut(\"@within(com.utils.annotation.InvokeLog)\")
切点函数3pointCutForMethod
AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar
1、获取所有的合格通知
0 条评论
下一页