吃透Spring源码(十八):AOP创建过程之注解配置方式

一,例子准备

切面类:LogUtil.java

@Aspect
@Component
public class LogUtil {

    @Pointcut("execution(public Integer com.mashibing.aop.annotation.service.MyCalculator.*(Integer,Integer))")
    public void myPointCut(){}

    @Around("myPointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Signature signature = pjp.getSignature();
        Object[] args = pjp.getArgs();
        Object result = null;
        try {
            System.out.println("log---环绕通知start:"+signature.getName()+"方法开始执行,参数为:"+Arrays.asList(args));
            result = pjp.proceed(args);
            System.out.println("log---环绕通知stop"+signature.getName()+"方法执行结束");
        } catch (Throwable throwable) {
            System.out.println("log---环绕异常通知:"+signature.getName()+"出现异常");
            throw throwable;
        }finally {
            System.out.println("log---环绕返回通知:"+signature.getName()+"方法返回结果是:"+result);
        }
        return result;
    }

    @Before(value = "myPointCut()")
    private int start(JoinPoint joinPoint){
        //获取方法签名
        Signature signature = joinPoint.getSignature();
        //获取参数信息
        Object[] args = joinPoint.getArgs();
        System.out.println("log---"+signature.getName()+"方法开始执行:参数是"+Arrays.asList(args));
        return 100;
    }

    @After("myPointCut()")
    public static void logFinally(JoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();
        System.out.println("log---"+signature.getName()+"方法执行结束。。。。。over");
    }


    @AfterReturning(value = "myPointCut()",returning = "result")
    public static void stop(JoinPoint joinPoint,Object result){
        Signature signature = joinPoint.getSignature();
        System.out.println("log---"+signature.getName()+"方法执行结束,结果是:"+result);
    }

    @AfterThrowing(value = "myPointCut()",throwing = "e")
    public static void logException(JoinPoint joinPoint,Exception e){
        Signature signature = joinPoint.getSignature();
        System.out.println("log---"+signature.getName()+"方法抛出异常:"+e.getMessage());
    }
}

需要被代理的类:MyCalculator.java

@Service
public class MyCalculator {
    public Integer add(Integer i, Integer j) throws NoSuchMethodException {
        Integer result = i+j;
        return result;
    }

    public Integer sub(Integer i, Integer j) throws NoSuchMethodException {
        Integer result = i-j;
        return result;
    }

    public Integer mul(Integer i, Integer j) throws NoSuchMethodException {
        Integer result = i*j;
        return result;
    }

    public Integer div(Integer i, Integer j) throws NoSuchMethodException {
        Integer result = i/j;
        return result;
    }

    public Integer show(Integer i){
        System.out.println("show .....");
        return i;
    }
}

配置类:SpringConfiguration.java

@Configuration
@ComponentScan(basePackages = "com.bobo.aop.annotation")
@EnableAspectJAutoProxy
public class SpringConfiguration {
}

测试类:MyTest.java

public class MyTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
    }
}

二,源码分析

1,AnnotationAwareAspectJAutoProxyCreator的注入

invokeBeanFactoryPostProcessors()方法中,会去执行ConfigurationClassPostProcessor(BFPP)的postProcessBeanDefinitionRegistry()方法,用于解析SpringConfiguration配置类:

@Configuration
@ComponentScan(basePackages = "com.bobo.aop.annotation")
@EnableAspectJAutoProxy
public class SpringConfiguration {
}

@EnableAspectJAutoProxy注解类:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

首先,解析@ComponentScan注解,把com.bobo.aop.annotation包名下面的被@Component注解修饰的LogUtil.javaMyCalculator.java注入到BeanFactory容器的BeanDefinitionMap中。

其次,解析@Import(AspectJAutoProxyRegistrar.class)注解,并实例化AspectJAutoProxyRegistrar类,发现其实现了ImportBeanDefinitionRegistrar接口,并且调用其registerBeanDefinitions()方法:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * 注册、升级和配置自动代理创建器依赖对应的proxyTargetClass属性在解析@Configuration类
	 */
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		// 注入
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

}

方法中调用AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)方法把AnnotationAwareAspectJAutoProxyCreator.class包装成BeanDefinition注入到BeanDefinitionMap中:

public abstract class AopConfigUtils {
    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {
		// 注入AnnotationAwareAspectJAutoProxyCreator.class
		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}
    
    private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        // 注入带BeanDefinitionMap中
        // AUTO_PROXY_CREATOR_BEAN_NAME=org.springframework.aop.config.internalAutoProxyCreator
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}
}

2,AnnotationAwareAspectJAutoProxyCreator类介绍

在这里插入图片描述

AnnotationAwareAspectJAutoProxyCreator继承于AspectJAwareAdvisorAutoProxyCreator,主要负责对使用注解定义的@Aspect进行查找和解析。

  • AspectJAwareAdvisorAutoProxyCreator:当我们使用xml进行定义切面时会注入此类
  • AnnotationAwareAspectJAutoProxyCreator:当我们使用@EnableAspectJAutoProxy注解方式来定义切面时会注入此类

AbstractAdvisorAutoProxyCreatorfindCandidateAdvisors()方法定义的是从BeanDefinitionMap中查找Advisor类,所以AspectJAwareAdvisorAutoProxyCreator继承了此方法,符合xml方式的定义查找Advisor类。

但是注解方式是对XMl的扩展,AnnotationAwareAspectJAutoProxyCreator继承于AspectJAwareAdvisorAutoProxyCreator并且重写了findCandidateAdvisors(),加入了注解的方式去扫描Advisor。例如去扫描我们本例子所定义的LogUtil切面类。

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
    /**
	 * 查找Advisor
	 */
	@Override
	protected List<Advisor> findCandidateAdvisors() {
        
		// 调用父类方法从BeanDefinitionMap中查找Advisor接口的BeanDefinition,并实例化
		List<Advisor> advisors = super.findCandidateAdvisors();
	
		if (this.aspectJAdvisorsBuilder != null) {
            // 注解方式的扩展,查找使用注解定义的@Aspect
			// 找到系统中使用@Aspect标注的bean,并且找到该bean中使用@Before,@After等标注的方法,
			// 将这些方法封装为一个个Advisor
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}
}

3,代理类的创建

本例子中依然是MyCalculator.java需要创建代理类,当然,配置类SpringConfiguration.java也是需要被创建代理的,我们前面文章已经对配置类做了分析,不了解的请移步吃透Spring源码(十六):ConfigurationClassPostProcessor详细介绍

这里以实例化MyCalculator来分析:

源码还是在getBean()—>doGetBean()—>createBean()—>doCreateBean()—>initializeBean()—>applyBeanPostProcessorsAfterInitialization()执行Bean的后置处理器AnnotationAwareAspectJAutoProxyCreator

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			// 获取当前bean的key:如果beanName不为空,则以beanName为key,如果为FactoryBean类型,
			// 前面还会添加&符号,如果beanName为空,则以当前bean对应的class为key
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			// 判断当前bean是否正在被代理,如果正在被代理则不进行封装
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// 如果它需要被代理,则需要封装指定的bean
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
    
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		
		// 获取当前bean的Advices和Advisors
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		// 对当前bean的代理状态进行缓存
		if (specificInterceptors != DO_NOT_PROXY) {
			// 对当前bean的代理状态进行缓存
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// 根据获取到的Advices和Advisors为当前bean生成代理对象
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			// 缓存生成的代理bean的类型,并且返回生成的代理bean
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}
}

调到父类的postProcessAfterInitialization()方法中,然后在wrapIfNecessary()方法中查找Advisor并创建代理类!

在wrapIfNecessary中查找Advisor会调用到子类AnnotationAwareAspectJAutoProxyCreator来查找注解定义的Advisor并实例化。

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
    /**
	 * 查找Advisor
	 */
	@Override
	protected List<Advisor> findCandidateAdvisors() {
        
		// 调用父类方法从BeanDefinitionMap中查找Advisor接口的BeanDefinition,并实例化
		List<Advisor> advisors = super.findCandidateAdvisors();
	
		if (this.aspectJAdvisorsBuilder != null) {
            // 注解方式的扩展,查找使用注解定义的@Aspect
			// 找到系统中使用@Aspect标注的bean,并且找到该bean中使用@Before,@After等标注的方法,
			// 将这些方法封装为一个个Advisor
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}
}

其中BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors()是对注解定义的Advisor进行查找和初始化:

public class BeanFactoryAspectJAdvisorsBuilder {
    /**
	 * 寻找Aspect注解的切面,然后解析他的方法,通过注解来生成对应的通知器Advisor
	 */
	public List<Advisor> buildAspectJAdvisors() {
		// 获取切面名字列表
		List<String> aspectNames = this.aspectBeanNames;

		// 缓存字段aspectNames没有值,注意实例化第一个单实例bean的时候就会触发解析切面
		if (aspectNames == null) {
			// 双重检查
			synchronized (this) {
				aspectNames = this.aspectBeanNames;
				if (aspectNames == null) {
					// 用于保存所有解析出来的Advisors集合对象
					List<Advisor> advisors = new ArrayList<>();
					// 用于保存切面的名称的集合
					aspectNames = new ArrayList<>();
					/**
					 * AOP功能中在这里传入的是Object对象,代表去容器中获取到所有的组件的名称,然后再
					 * 进行遍历,这个过程是十分的消耗性能的,所以说Spring会再这里加入了保存切面信息的缓存。
					 * 但是事务功能不一样,事务模块的功能是直接去容器中获取Advisor类型的,选择范围小,且不消耗性能。
					 * 所以Spring在事务模块中没有加入缓存来保存我们的事务相关的advisor
					 */
					String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
							this.beanFactory, Object.class, true, false);
					// 遍历我们从IOC容器中获取处的所有Bean的名称
					for (String beanName : beanNames) {
						// 判断当前bean是否为子类定制的需要过滤的bean
						if (!isEligibleBean(beanName)) {
							continue;
						}
						
						// 通过beanName去容器中获取到对应class对象
						Class<?> beanType = this.beanFactory.getType(beanName, false);
						if (beanType == null) {
							continue;
						}
						// 判断当前bean是否使用了@Aspect注解进行标注
						if (this.advisorFactory.isAspect(beanType)) {
							aspectNames.add(beanName);
							// 对于使用了@Aspect注解标注的bean,将其封装为一个AspectMetadata类型。
							// 这里在封装的过程中会解析@Aspect注解上的参数指定的切面类型,如perthis
							// 和pertarget等。这些被解析的注解都会被封装到其perClausePointcut属性中
							AspectMetadata amd = new AspectMetadata(beanType, beanName);
							// 判断@Aspect注解中标注的是否为singleton类型,默认的切面类都是singleton类型
							if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
								// 将BeanFactory和当前bean封装为MetadataAwareAspect-
								// InstanceFactory对象,这里会再次将@Aspect注解中的参数都封装
								// 为一个AspectMetadata,并且保存在该factory中
								MetadataAwareAspectInstanceFactory factory =
										new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
								// 通过封装的bean获取其Advice,如@Before,@After等等,并且将这些
								// Advice都解析并且封装为一个个的Advisor
								List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
								// 如果切面类是singleton类型,则将解析得到的Advisor进行缓存,
								// 否则将当前的factory进行缓存,以便再次获取时可以通过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.
								// 如果@Aspect注解标注的是perthis和pertarget类型,说明当前切面
								// 不可能是单例的,因而这里判断其如果是单例的则抛出异常
								if (this.beanFactory.isSingleton(beanName)) {
									throw new IllegalArgumentException("Bean with name '" + beanName +
											"' is a singleton, but aspect instantiation model is not singleton");
								}
								// 将当前BeanFactory和切面bean封装为一个多例类型的Factory
								MetadataAwareAspectInstanceFactory factory =
										new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
								// 对当前bean和factory进行缓存
								this.aspectFactoryCache.put(beanName, factory);
								advisors.addAll(this.advisorFactory.getAdvisors(factory));
							}
						}
					}
					this.aspectBeanNames = aspectNames;
					return advisors;
				}
			}
		}

		if (aspectNames.isEmpty()) {
			return Collections.emptyList();
		}
		// 通过所有的aspectNames在缓存中获取切面对应的Advisor,这里如果是单例的,则直接从advisorsCache
		// 获取,如果是多例类型的,则通过MetadataAwareAspectInstanceFactory立即生成一个
		List<Advisor> advisors = new ArrayList<>();
		for (String aspectName : aspectNames) {
			List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
			// 如果是单例的Advisor bean,则直接添加到返回值列表中
			if (cachedAdvisors != null) {
				advisors.addAll(cachedAdvisors);
			}
			else {
				// 如果是多例的Advisor bean,则通过MetadataAwareAspectInstanceFactory生成
				MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
				advisors.addAll(this.advisorFactory.getAdvisors(factory));
			}
		}
		return advisors;
	}
}

具体Advisor类的创建,和代理类的创建和上一篇xml定义方式的创建过程是一样的,这里就不再介绍了,请直接移步到上一篇文章即可:吃透Spring源码(十七):AOP创建过程之XML配置方式

三,总结

  • 注解方式的Advisor扫描是通过AnnotationAwareAspectJAutoProxyCreator类来完成的,扫描Advisor的时机与xml方式不同,注解的扫描时机是在创建代理类的时候(在BPP的后置处理器里面),而XML方式的Advisor扫描是在实例化第一个对象之前的AbstractAutoProxyCreator#applyBeanPostProcessorsBeforeInstantiation()方法中

  • AnnotationAwareAspectJAutoProxyCreator继承于AspectJAwareAdvisorAutoProxyCreatorAspectJAwareAdvisorAutoProxyCreator的基础上做了注解的扩展。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃透Java

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值