一,例子准备
切面类: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.java
和MyCalculator.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
注解方式来定义切面时会注入此类
AbstractAdvisorAutoProxyCreator
的findCandidateAdvisors()
方法定义的是从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
继承于AspectJAwareAdvisorAutoProxyCreator
在AspectJAwareAdvisorAutoProxyCreator
的基础上做了注解的扩展。