SpringAop基于注解的源码解析

SpringAop基于注解的源码解析


 1、简介
AOP 的全称是 “Aspect Oriented Programming”,即面向切面编程。在 AOP 的思想里面,周边功能(比如性能统计,日志,事务管理等)被定义为切面,核心功能和切面功能分别
独立进行开发,然后把核心功能和切面功能“编织”在一起,这就叫 AOP。AOP 能够将那些与业务无关,却为业务模块所共同调用的
逻辑封装起来,便于减少系统的重复代码,降低模块间
的耦合度,并有利于未来的可拓展性和可维护性。
  • 连接点(Join point):能够被拦截的地方,在Spring中,连接点主要指的是方法调用。Spring AOP 是基于动态代理的,每个成员方法都可以称之为连接点。
  • 切点(Pointcut):每个方法都可以称之为连接点,我们定位到具体某一个或一些方法就称为切点。
  • 增强/通知(Advice):表示添加到切点的一段逻辑代码,并定位连接点的方位信息,简单来说就定义了是干什么的,具体是在哪干。
  • 织入(Weaving):将增强/通知添加到目标类的具体连接点上的过程。
  • 引入/引介(Introduction):允许我们向现有的类添加新方法或属性,是一种特殊的增强。
  • 切面(Aspect):切面由切点和增强/通知组成,它既包括了横切逻辑的定义、也包括了连接点的定义。

2、五种通知分类
1.前置通知(Before Advice):在目标方法被调用前调用通知功能。
2.后置通知(After Advice):是一种通用的后置通知,它会在目标方法正常完成(无论方法是否有返回值,也不管方法是否抛出了未被捕获的异常)后执行。
换句话说,只要方法执行完毕(无论以何种方式结束),对应的After Advice就会被触发。
特点:
独立于方法返回状态:无论方法是否成功返回一个值,或者是否抛出了异常,After Advice都会被执行。
无法访问方法返回值:由于这种通知类型并不关心方法的具体返回情况,因此在After Advice中无法直接访问到方法的返回值。通常用于资源清理、日志记录等场景:由于不依赖于方法执行
结果,After Advice适用于需要在方法执行结束后进行统一处理的任务,如关闭数据库连接、释放系统资源、记录方法执行耗时等与方法返回无关的操作。

3.返回通知(After-returning):是一种特殊的后置通知,它仅在目标方法成功执行且返回非null值之后才执行。也就是说,只有当方法没有抛出异常并且确实
返回了一个有效结果时,After-returning Advice才会被触发。由于可以访问到方法的返回值,After-returning Advice适合用于对方法返回结果进行
进一步加工、验证、缓存或者触发基于返回值的业务逻辑。
4.异常通知(After-throwing):在目标方法抛出异常之后调用通知功能。
5.环绕通知(Around):把整个目标方法包裹起来,在被调用前和调用之后分别调用通知功能。

3、AOP的使用示例
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.0.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.0.0.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.8.11</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.11</version>
    </dependency>
3.1、创建AOP切面、配置切入点
@Aspect
@Component
public class AspectJTest {

    @Pointcut("execution(public * com.dw.study.service.IOCService.hello(..))")
    public void testAOP(){}

    @Before("testAOP()")
    public void before(){
        System.out.println("before testAOP...");
    }

    @After("testAOP()")
    public void after(){
        System.out.println("after testAOP...");
    }

    @Around("testAOP()")
    public Object around(ProceedingJoinPoint p){
        System.out.println("around before testAOP...");
        Object o = null;
        try {
            o = p.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("around after testAOP...");
        return o;
    }
}
3.2、创建业务类
public interface IOCService {
    public String hello();
}
public class IOCServiceImpl implements IOCService {

  @Override
  public String hello() {
    System.out.println("hello,IOC");
    return "Hello,IOC";
  }
}
@Configuration
@EnableAspectJAutoProxy
public class AnnotationConfig {
  @Bean
  public IOCService iocService() {
    return new IOCServiceImpl();
  }
}
// 测试
public static void main(String args[]) {
  ApplicationContext context = new AnnotationConfigApplicationContext("com.dw.study.config");
  IOCService iocService = context.getBean(IOCService.class);
  iocService.hello();
}
3.3、运行结果
around before testAOP...
before testAOP...
hello,IOC
around after testAOP...
after testAOP...


4、源码解析

AOP实现的关键:
1、解析所有@Aspect注解的类,获取所有切入点(@Before、@After等通知注解)。
2、基于1中获取到的切入点,对每个bean,生成代理类。
从 @EnableAspectJAutoProxy 注解开始, 里面有一个@Import(AspectJAutoProxyRegistrar.class)。关于@Import注解,[可以参考之前的文章]。
主要作用是动态地往Spring IOC 中注册Bean。下面我们看 AspectJAutoProxyRegistrar 这个类。核心代码如下:
// 从这方法往下
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// 找到调用的核心org.springframework.aop.config.AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(...)
// 这个方法主要往Spring IOC中注册了一个 AnnotationAwareAspectJAutoProxyCreator 这个是核心
registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source)
AnnotationAwareAspectJAutoProxyCreator 如何往Spring IOC中注册所有的切面并生成代理呢?
1、AnnotationAwareAspectJAutoProxyCreator的初始化?

 可以看出它最终实现了InstantiationAwareBeanPostProcessor接口, 初始化工作在AbstractAutoProxyCreator类的postProcessBeforeInstantiation(...)方法中完成,这个方法在哪里调用的呢?

可以参考[InstantiationAwareBeanPostProcessor这个接口的执行流程]

接下来我们看看实例化的过程:
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        Object cacheKey = getCacheKey(beanClass, beanName);

        if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            // 重点看shouldSkip()这个方法
            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }
        // ....
org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.shouldSkip()
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
        // 获取所有切面
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
    }
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors()
protected List<Advisor> findCandidateAdvisors() {
        // 获取所有Beanfactory中所有的 Advisor
        List<Advisor> advisors = super.findCandidateAdvisors();
        // Build Advisors for all AspectJ aspects in the bean factory.
        if (this.aspectJAdvisorsBuilder != null) {
        // 从容器中取出所有的Bean, 如果类上面注解了@Aspect则进行处理
            advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        }
        return advisors;
    }
org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors()
public List<Advisor> buildAspectJAdvisors() {
    .....
    // 如果类上注解了@Aspect则进行处理
    if (this.advisorFactory.isAspect(beanType)) {
          List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
        if (this.beanFactory.isSingleton(beanName)) {
        // 找到所有Advisor并放入缓存中,在后置处理生成代理时中会用到
            this.advisorsCache.put(beanName, classAdvisors);
        }
        ...
    }
    .....
 }
org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getAdvisors
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
       List<Advisor> advisors = new LinkedList<>();
       // getAdvisorMethods()获取切面Bean所有方法,并按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class) 顺序排序
      for (Method method : getAdvisorMethods(aspectClass)) {
      // 根据 method 构建Advisor
          Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
          if (advisor != null) {
              advisors.add(advisor);
          }
      }
}
org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getAdvisor
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
            int declarationOrderInAspect, String aspectName) {
        // ....
        // 创建Advisor实例化对象
        return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
    }
    
    public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
            Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
            MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
            ....
            // 实例化Advisor
            this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
    }
    // 具体实例化Advice
    private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
        Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
                this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
        return (advice != null ? advice : EMPTY_ADVICE);
    }
     // 具体实例化Advice
    public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
            MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { 
            .....
    // 根据不同的注解创建不同的Advice
    AbstractAspectJAdvice springAdvice;
        switch (aspectJAnnotation.getAnnotationType()) {
            case AtBefore:
                springAdvice = new AspectJMethodBeforeAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            case AtAfter:
                springAdvice = new AspectJAfterAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            case AtAfterReturning:
                springAdvice = new AspectJAfterReturningAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
                if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                    springAdvice.setReturningName(afterReturningAnnotation.returning());
                }
                break;
            case AtAfterThrowing:
                springAdvice = new AspectJAfterThrowingAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
                if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                    springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
                }
                break;
            case AtAround:
                springAdvice = new AspectJAroundAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            case AtPointcut:
                if (logger.isDebugEnabled()) {
                    logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
                }
                return null;
            default:
                throw new UnsupportedOperationException(
                        "Unsupported advice type on method: " + candidateAdviceMethod);
        }        
     }
到这一步,前置处理已经完成, 找到所有的Advisor放入BeanFactoryAspectJAdvisorsBuilder的 advisorsCache = new ConcurrentHashMap<>();

2、后置处理-生成代理类

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization
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;
    }
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        // 根据当前Bean获取匹配到的Advisor
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 生成代理
            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;
    }
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy
// 创建代理
org.springframework.aop.framework.ProxyCreatorSupport.createAopProxy
org.springframework.aop.framework.DefaultAopProxyFactory.createAopProxy
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

  @Override
  public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
      Class<?> targetClass = config.getTargetClass();
      if (targetClass == null) {
        throw new AopConfigException("TargetSource cannot determine target class: " +
                "Either an interface or a target is required for proxy creation.");
      }
      // 目标类是接口或者代理类,则使用 JDK 动态代理
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
        return new JdkDynamicAopProxy(config);
      }
      // 使用CGLIB代理
      return new ObjenesisCglibAopProxy(config);
    } else {
      return new JdkDynamicAopProxy(config);
    }
  }
}
// 获取代理对象(两种实现JDK代理、CGLIB代理
org.springframework.aop.framework.ProxyFactory.getProxy(java.lang.ClassLoader)


3、调用逻辑参考

org.springframework.aop.framework.JdkDynamicAopProxy.invoke()
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor.intercept()






 
posted @ 2024-07-23 12:04  邓维-java  阅读(161)  评论(0)    收藏  举报