当前位置: 首页 > news >正文

AoP-@Aspect注解处理源码解析

对主类使用@EnableAspectJAutoProxy注解后会导入组件,

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

AspectJAutoProxyRegistrar类实现了ImportBeanDefinitionRegistrar接口中的registerBeanDefinitions()方法,此方法会向容器中注册AnnotationAwareAspectJAutoProxyCreator组件。

	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);}

AnnotationAwareAspectJAutoProxyCreator类继承的AbstractAutoProxyCreator类实现InstantiationAwareBeanPostProcessor接口中的postProcessBeforeInstantiation()方法,在Bean实例化之前会被调用,用来创建Bean的代理对象,aop正是通过这个接口实现的。
这个要做的事情就是先获取容器中增强型Bean,然后再对其他Bean进行增强。

	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {Object cacheKey = getCacheKey(beanClass, beanName);//判断是否为基础Beanif (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {if (this.advisedBeans.containsKey(cacheKey)) {return null;}if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return null;}}TargetSource targetSource = getCustomTargetSource(beanClass, beanName);if (targetSource != null) {if (StringUtils.hasLength(beanName)) {this.targetSourcedBeans.add(beanName);}Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}return null;}

先判断是否为基础Bean,并且将基础Bean使用advisedBeans(private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);)缓存,有三类Bean为基础型Bean:

  1. 实现了Advice等接口的Bean
	protected boolean isInfrastructureClass(Class<?> beanClass) {boolean retVal = Advice.class.isAssignableFrom(beanClass) ||Pointcut.class.isAssignableFrom(beanClass) ||Advisor.class.isAssignableFrom(beanClass) ||AopInfrastructureBean.class.isAssignableFrom(beanClass);if (retVal && logger.isTraceEnabled()) {logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");}return retVal;}
  1. Bean的name是以".ORIGINAL"结尾
// String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL";static boolean isOriginalInstance(String beanName, Class<?> beanClass) {if (!StringUtils.hasLength(beanName) || beanName.length() !=beanClass.getName().length() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX.length()) {return false;}return (beanName.startsWith(beanClass.getName()) &&beanName.endsWith(AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX));}
  1. 使用了@Aspect注解的Bean,这是重点分析的AspectJAwareAdvisorAutoProxyCreator#shouldSkip()方法的逻辑,注意这里优先调用子类AspectJAwareAdvisorAutoProxyCreator的shouldSkip()方法,先从容器中找出用来实现切面功能的@Aspect注解标注的Bean,然后通过name判断是否为当前的Bean,即当前的Bean如果被@Aspect标注则跳过处理。
// AspectJAwareAdvisorAutoProxyCreator.java@Overrideprotected boolean shouldSkip(Class<?> beanClass, String beanName) {// TODO: Consider optimization by caching the list of the aspect namesList<Advisor> candidateAdvisors = findCandidateAdvisors();for (Advisor advisor : candidateAdvisors) {if (advisor instanceof AspectJPointcutAdvisor &&((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {return true;}}return super.shouldSkip(beanClass, beanName);}

看下怎么从容器中获取@Aspect的Advisor,调用BeanFactoryAdvisorRetrievalHelper.java#findAdvisorBeans()找到实现了Advisor接口的Bean,作为Advisor通知,这个不作分析,因为现在很少这样实现,看下怎么获取@Aspect的Advisor,首先找到容器中所有Bean的name,然后获取Bean的Class,判断是否使用了@Aspect注解。

	public List<Advisor> buildAspectJAdvisors() {List<String> aspectNames = this.aspectBeanNames;if (aspectNames == null) {synchronized (this) {aspectNames = this.aspectBeanNames;if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();aspectNames = new ArrayList<>();String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);for (String beanName : beanNames) {if (!isEligibleBean(beanName)) {continue;}// We must be careful not to instantiate beans eagerly as in this case they// would be cached by the Spring container but would not have been weaved.Class<?> beanType = this.beanFactory.getType(beanName, false);if (beanType == null) {continue;}if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);AspectMetadata amd = new AspectMetadata(beanType, beanName);if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {MetadataAwareAspectInstanceFactory factory =new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);if (this.beanFactory.isSingleton(beanName)) {this.advisorsCache.put(beanName, classAdvisors);}else {this.aspectFactoryCache.put(beanName, factory);}advisors.addAll(classAdvisors);}else {// Per target or per this.if (this.beanFactory.isSingleton(beanName)) {throw new IllegalArgumentException("Bean with name '" + beanName +"' is a singleton, but aspect instantiation model is not singleton");}MetadataAwareAspectInstanceFactory factory =new PrototypeAspectInstanceFactory(this.beanFactory, beanName);this.aspectFactoryCache.put(beanName, factory);advisors.addAll(this.advisorFactory.getAdvisors(factory));}}}this.aspectBeanNames = aspectNames;return advisors;}}}if (aspectNames.isEmpty()) {return Collections.emptyList();}List<Advisor> advisors = new ArrayList<>();for (String aspectName : aspectNames) {List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);if (cachedAdvisors != null) {advisors.addAll(cachedAdvisors);}else {MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);advisors.addAll(this.advisorFactory.getAdvisors(factory));}}return advisors;}

然后通过ReflectiveAspectJAdvisorFactory.java#getAdvisors()获取Bean中增强型的方法,即被@Around, @Before, @After, @AfterReturning, @AfterThrowing注解标注的方法。

	public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();validate(aspectClass);// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator// so that it will only instantiate once.MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);List<Advisor> advisors = new ArrayList<>();for (Method method : getAdvisorMethods(aspectClass)) {Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);if (advisor != null) {advisors.add(advisor);}}// If it's a per target aspect, emit the dummy instantiating aspect.if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);advisors.add(0, instantiationAdvisor);}// Find introduction fields.for (Field field : aspectClass.getDeclaredFields()) {Advisor advisor = getDeclareParentsAdvisor(field);if (advisor != null) {advisors.add(advisor);}}return advisors;}

然后在getAdvisor()中找到切点表达式,即@Pointcut注解标注的方法,再使用InstantiationModelAwarePointcutAdvisorImpl对切点表达式和通知方法进行封装。

	public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect, String aspectName) {validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());if (expressionPointcut == null) {return null;}return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);}
http://www.lryc.cn/news/20501.html

相关文章:

  • 宝塔搭建实战php悟空CRM前后端分离源码-vue前端篇(二)
  • FastASR+FFmpeg(音视频开发+语音识别)
  • 二分查找的实现代码JAVA
  • cesium: 设置skybox透明并添加背景图 ( 003 )
  • 【python】类的详解
  • 西安银行就业总结
  • JavaScript Window
  • 那些开发过程中需要遵守的开发规范
  • EFCore 基础入门教程
  • HTML5 Drag and Drop
  • 惠普m1136打印机驱动程序安装教程
  • 数据增强,扩充了数据集,增加了模型的泛化能力
  • MySQL/Oracle获取当前时间几天/分钟前的时间
  • 如何在Wordpress中使用wp_nav_menu()在<li>及a标记中添加Class
  • Chat Support Board WordPress聊天插件 v3.5.8
  • 2022年网络安全竞赛——数字取证调查attack.pcapng
  • 2023最新MongoDB规范
  • gcc的使用,调试工具gdb的使用
  • Python变量的定义和使用
  • SSM框架-AOP概述、Spring事务
  • 一文搞定Android Vsync原理简析
  • 第八届蓝桥杯省赛 C++ B组 - K 倍区间
  • UDP与TCP协议
  • rosbag相关使用工具
  • 数据结构与算法—栈stack
  • 【学习笔记】[ARC150F] Constant Sum Subsequence
  • Node.js实现大文件断点续传—浅析
  • Spring Cloud Nacos源码讲解(九)- Nacos客户端本地缓存及故障转移
  • MySQL知识点小结
  • MySQL关于NULL值,常见的几个坑