十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
本篇内容主要讲解“如何理解AOP中JDK代理实现的原理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解AOP中JDK代理实现的原理”吧!
在静宁等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供网站设计制作、成都网站设计 网站设计制作按需定制,公司网站建设,企业网站建设,品牌网站制作,成都全网营销,成都外贸网站制作,静宁网站建设费用合理。
动态代理技术在Spring AOP中分为两种:
提供一种在运行时创建一个实现了一组接口的新类。由于Java是不支持实例化接口的,因此JDK会在运行期间生成一个代理类对给定的接口进行实现,在调用该代理类接口的时候,将实现逻辑转发到调用处理器中(Invocation handler)。
JDK进行动态代理的类必须实现接口
代理类是java.lang.reflect.Proxy子类,类名以$Proxy开始。
CGLIB(Code Generation Library)是基于ASM(对Java字节码进行操作的框架)的类库。
Spring AOP中,如果被代理类(targetObject)没有实现接口,即无法通过JDK的动态代理生成代理类,那么就会选择CGLIB来进行代理。
CGLIB动态代理的原理:创建一个targetObject的子类,覆盖掉需要父类的方法,在覆盖的方法中对功能进行增强。
注意,由于是采用继承覆盖的方式,所以由final方法修饰的类无法使用CGLIB进行代理。
JDK动态代理要求被代理类实现接口,切面类需要实现InvocationHandler。
CGLIB采用继承+方法覆盖实现切面,重写方法将逻辑委托给MethodInterceptor#intercept。
CGLIB对代理类基本没有限制,但是需要注意被代理的类不可以被final修饰符和private修饰,因为Java无法重写final类/private的方法。
@EnableAspectJAutoProxy注解是Spring AOP开启的标志,在启动类标记此注解,即启用可加载对应的切面类逻辑。此注解的ElementType为TYPE,表示标记在类上。
同时用 @Retention(RetentionPolicy.RUNTIME)声明了注解在运行时得到保留。此外最重要的是使用了 @Import(AspectJAutoProxyRegistrar.class)来注册AOP的。
@EnableAspectJAutoProxy注解正是通过@Import的方式来将 AspectJAutoProxyRegistrar类注册成Spring的Bean,以便在容器解析切面类时派上用场。那么AspectJAutoProxyRegistrar类的作用是什么?
@Import(AspectJAutoProxyRegistrar.class)
@EnableAspectJAutoProxy支持处理标有AspectJ的@Aspect批注的组件,用户可以主动声明proxyTargetClass来指定Spring AOP使用哪种动态代理方式来创建代理类(默认使用基于实现接口的JDK动态代理方式)。
使用CGLIB动态代理来创建代理类
@Configuration @EnableAspectJAutoProxy(proxyTargetClass=true) @ComponentScan("com.libo") public class AppConfig { // ... }
为了解决一些由于代理引发的切面失效问题,Spring AOP在Spring 4.3.1后引入了AopContext类来将代理类的引用存储在ThreadLocal中,通过AopContext可以快速获取当前类的代理类。
默认为不支持,如果声明为true,即可使用AopContext获取代理类,同时,为了使用AspectJ,需要确保当前jar仓库存在aspectjweaver。
通过@Import注册AspectJAutoProxyRegistrar,通常情况下,我们的启动类本身也是一个Bean,Spring支持使用 @Import来导入一个没有标记任何Spring注解的类来将该Java类注册成Spring的Bean。
Registers an AnnotationAwareAspectJAutoProxyCreator against the current BeanDefinitionRegistry as appropriate based on a given @EnableAspectJAutoProxy annotation.
根据当前BeanDefinitionRegistry在适当的位置注册AnnotationAwareAspectJAutoProxyCreator。
用来导入一些特殊的BeanDefinition,Spring在处理 @Configuration时,会去扫描是否有通过 @Import标签导入的类,对ImportBeanDefinitionRegistrar这类接口,还会执行其中的registerBeanDefinitions方法。
AspectJAutoProxyRegistrar:实现了ImportBeanDefinitionRegistrar接口,用来注册AspectJAnnotationAutoProxyCreator,也就是支持注解驱动(同时兼容XML)解析的AspectJ自动代理创建器。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 向容器注册AspectJAnnotationAutoProxyCreator AopConfigUtils. registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); // 如果@EnableAspectJAutoProxy上存在标签内容 if (enableAspectJAutoProxy != null) { // proxyTargetClass为true,则强制指定AutoProxyCreator使用CGLIB进行代理 if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } // 是否开启exposeProxy特性 if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } }
向容器注册AspectJAnnotationAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
随后解析 @EnableAspectJAutoProxy注解上的元数据来决定是否开启上述我们讲到的proxyTargetClass和exposeProxy特性.
为了了解registerBeanDefinitions方法的执行链路和调用时机,我们使用IDE的debug来查看调用栈分析执行流程。
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass(configClass.getImportBeanDefinitionRegistrars())
这行代码,从代码的语义上我们可以大致可以猜出来,这是解析当前配置类上是否存在通过@Import导入的实现了ImportBeanDefinitionRegistrar的类。
最终会调用AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,注册一个AnnotationAwareAspectJAutoProxyCreator,该类属于AOP的核心类。
执行AspectJAutoProxyRegistrar#registerBeanDefinitions方法。
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
@Nullable public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); }
从上面的代码可以看出来AnnotationAwareAspectJAutoProxyCreator这个类作为实际操作者,查看该类的继承关系图。(省略一些不必要的类)。
首先看第一个接口,BeanPostProcessor,这个接口作为顶层接口,肯定不会被外部直接调用,所以大概率是底下的几个具体实现类被调用,然后通过判断是不是InstantiationAwareBeanPostProcessor接口的类型,再执行相应逻辑,带着这个疑惑,来看源码。
AbstractAutoProxyCreator通过postProcessAfterInitialization实现AOP功能。
// 在实例化之后进行操作容器对象 @Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // beanName不为空,并且存在于targetSourcedBeans中,也就是自定义的 // TargetSource被解析过了 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } // 如果Bean为advisedBeans,也不需要被代理 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // isInfrastructureClass和shouldSkip的作用: // 识别切面类,加载切面类成advisors // 为什么又执行一次是因为存在循环依赖的情况下无法加载advisor if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. // 返回匹配当前Bean的所有Advice、Advisor、Interceptor Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 创建Bean对应的代理,SingletonTargetSource用于封装实现类的信息 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } // 下次代理不需要重复生成了 this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
判断缓存中是否存在当前Bean或者是当前Bean已经被代理过了,那么直接返回bean.
尝试再次加载advisor,避免由于循环依赖导致advisor加载不完整.
获取当前bean符合的advisor数组.
创建代理类.
本文来分析getAdvicesAndAdvisorsForBean方法是如何在所有的advisors中找到匹配的advisor的.
@Override @Nullable protected Object[] getAdvicesAndAdvisorsForBean( Class> beanClass, String beanName, @Nullable TargetSource targetSource) { Listadvisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); } //这里调用了findEligibleAdvisors来寻找合适的advisors,如果返回的集合为空,那么 // 最后返回null. // 如果返回了advisors,将其数组化返回. protected List findEligibleAdvisors(Class> beanClass, String beanName) { //BeanFactory 中所有 Advisor 的实现 List candidateAdvisors = findCandidateAdvisors(); // 有资格的 Advisor List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; } //首先获取之前解析过的advisors列表-candidateAdvisors,这里是所有的切面类解析成的advisors. //在candidateAdvisors中找到当前Bean匹配的advisor-findAdvisorsThatCanApply. //将获取到的eligibleAdvisors进行排序. protected List findCandidateAdvisors() { Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); return this.advisorRetrievalHelper.findAdvisorBeans(); } protected List findAdvisorsThatCanApply( List candidateAdvisors, Class> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null); } } public static List findAdvisorsThatCanApply(List candidateAdvisors, Class> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } // 存储最终匹配的Advisor集合 List eligibleAdvisors = new ArrayList<>(); for (Advisor candidate : candidateAdvisors) { // 当前advisor对象是否实现了IntroductionAdvisor接口 if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { // already processed continue; } // canApply->判断当前的advisor的pointcut表达式是否匹配当前class if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; } //最终是调用了AopUtils.findAdvisorsThatCanApply来筛选匹配Bean的Advisors.
ProxyFactory 对象中有要代理的bean和这个Bean上的advisor
Bean使用哪种代理
当Bean实现接口时,Spring就会用JDK的动态代理。 当Bean没有实现接口时,Spring会自动使用CGlib实现,但是前提是项目中导入了CGlib的相关依赖,否则Spring只能使用JDK来代理那些没有实现接口的类,这样生成的代理类会报错。 AopProxy有两个实现类JdkDynamicAopProxy和CglibAopProxy。都是构造 ReflectiveMethodInvocation.proceed()。
JdkDynamicAopProxy
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); retVal = invocation.proceed();
CglibAopProxy
// CglibMethodInvocation 继承于 ReflectiveMethodInvocation retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
ReflectiveMethodInvocation.proceed()
public Object proceed() throws Throwable { // 当所有拦截器都执行后,调用目标类的目标方法 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // 动态拦截器 InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. return proceed(); } } else { // MethodInterceptor的实现类在处理完自己的逻辑后,还是会调用procee(),传入this就是为了达到这个目的 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
Spring用来处理应用上下文中被@AspectJ注解标记的类的。继续进入registerOrEscalateApcAsRequired方法中看看注册流程.
org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired private static BeanDefinition registerOrEscalateApcAsRequired( Class> cls, BeanDefinitionRegistry registry, @Nullable Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); // 当前容器是否包含 org.springframework.aop.config.internalAutoProxyCreator if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } // 将传入的class包装成BeanDefinition,然后注册到容器中,并讲其order的执行顺序 //调整为最优。 // 在aop中,这里会注册AnnotationAwareAspectJAutoProxyCreator.class这个类 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; }
首先查看当前容器中是否包含
org.springframework.aop.config.internalAutoProxyCreator的BeanDefiniton.
如果没有,将传入的class(在此处传入了AnnotationAwareAspectJAutoProxyCreator.class)包装成RootBeanDefinition,然后注册到容器中.
设置proxyTargetClass与exposeProxy
我们看一下如何设置proxyTargetClass即可,大体上设置proxyTargetClass与exposeProxy的逻辑都是相通的.
// 如果@EnableAspectJAutoProxy上存在标签内容 if (enableAspectJAutoProxy != null) { // 如果proxyTargetClass为true,则强制指定AutoProxyCreator使用CGLIB进行代理 if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } // 是否开启exposeProxy特性 if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } }
进入AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); AopConfigUtils#forceAutoProxyCreatorToUseClassProxying public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) { // 如果容器中包含 org.springframework.aop.config.internalAutoProxyCreator if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { // 取出 org.springframework.aop.config.internalAutoProxyCreator的BeanDefinition BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); // 设置proxyTargetClass为true definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE); } }
如容器中包含名org.springframework.aop.config.internalAutoProxyCreator,那么取出该BeanDefinition,设置proxyTargetClass为true。
Spring为了兼容不同的BeanDefinition持有不同的属性值,将它们都抽象成了MutablePropertyValues,definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE),就跟我们平时JavaBean中的set方法是一样的.
简单理解 @Import和ImportBeanDefinitionRegistrar,下面我们通过两个用例来理解@Import和ImportBeanDefinitionRegistrar
通过@Import导入类让Spring进行管理
public class NeedImportBean { public void doSomething(){ Logger.getGlobal().info("Through @Import registry to a bean "); } }
在启动类中将NeedImportBean导入
/** * @author jaymin * 2020/11/30 20:13 */ @Configuration @ComponentScan(value = "com.xjm") @Import(NeedImportBean.class) @EnableAspectJAutoProxy public class ApplicationConfig { public static AnnotationConfigApplicationContext getApplicationContext() { return new AnnotationConfigApplicationContext(ApplicationConfig.class); } } //对NeedImportBean做getBean public class BeanFactoryDemo { public static void main(String[] args) throws Exception { AnnotationConfigApplicationContext applicationContext = ApplicationConfig.getApplicationContext(); NeedImportBean needImportBean = applicationContext.getBean(NeedImportBean.class); } }
NeedImportBean实现ImportBeanDefinitionRegistrar接口,然后验证两个点:
是否会回调registerBeanDefinitions方法。
通过getBean是否能获取NeedImportBean
public class NeedImportBean implements ImportBeanDefinitionRegistrar{ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { Logger.getGlobal().info("Through implements ImportBeanDefinitionRegistrar and @Import to callback me."); } public void doSomething(){ Logger.getGlobal().info("Through @Import registry to a bean "); } }
refresh中激活后置处理器ConfigurationClassPostProcessor加载@Configuration上的元数据
首先容器会加载refresh方法。
执行invokeBeanFactoryPostProcessors(beanFactory);激活工厂级别的后置处理器。
由于启动类都是被 @Configuration标记的,Spring会使用ConfigurationClassPostProcessor来解析被 @Configuration的类。
使用ConfigurationClassBeanDefinitionReader来加载配置类解析成BeanDefinition。
到此,相信大家对“如何理解AOP中JDK代理实现的原理”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!