Spring AOP 源码解析上

本文基于Spring5.2.X版本.

Spring AOP 总体流程:

  1、注册解析AOP服务

  2、解析和加载横切逻辑

  3、将横切逻辑织入bean中

Spring AOP 的原理其实就是动态代理。代理模式接口 + 真实实现类 + 代理类,其中 真实实现类 和 代理类 都要实现接口,实例化的时候要使用代理类。Spring AOP 需要做的是生成这么一个代理类,不多说 直接code吧

定义一个切面类

import com.test.introduction.LittleUniverse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Order(1)
@Component
public class ServiceAspect {

    @Pointcut("execution(* com.test.service..*.*(..))")
    public void embed(){}
    @Before("embed()")
    public void before(JoinPoint joinPoint){

        System.out.println("ServiceAspect开始调用 " + joinPoint.toString());
    }
    @After("embed()")
    public void after(JoinPoint joinPoint){
        System.out.println("ServiceAspect调用完成 " + joinPoint );
    }
    @Around("embed()")
    public Object aroundMe(JoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object returnValue = null;
        System.out.println("ServiceAspect开始计时 " + joinPoint);

            returnValue = ((ProceedingJoinPoint)joinPoint).proceed();
            System.out.println("ServiceAspect执行成功,结束计时 " + joinPoint);

            long endTime = System.currentTimeMillis();
            System.out.println("ServiceAspect总耗时 "+ joinPoint + "[" + (endTime - startTime) + "]ms");

        return returnValue;
    }
    @AfterReturning(pointcut = "embed()", returning = "returnValue")
    public void afterReturning(JoinPoint joinPoint, Object returnValue){
        System.out.println("ServiceAspect无论是空还是有值都返回  " + joinPoint + ",返回值[" + returnValue + "]");
    }
    @AfterThrowing(pointcut = "embed()", throwing = "exception")
    public void afterThrowing(JoinPoint joinPoint,  Exception exception){
        System.out.println("ServiceAspect抛出异常通知  " + joinPoint + "   " + exception.getMessage() );
    }
    @DeclareParents(value = "com.test.controller..*", defaultImpl = com.test.introduction.LittleUniverseImpl.class)
    public LittleUniverse littleUniverse;
}

定义service

 

public interface HiService {
    void sayHi();
    String justWantToSayHi();
}  

 

serviceImpl

@Service
public class HiServiceImpl implements HiService {
    @Override
    public void sayHi() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Hi everyone");
    }

    @Override
    public String justWantToSayHi() {
        return "Just want to say hi";
    }
}

 

controller

import com.test.service.HiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class HiController {
	@Autowired
	private HiService hiService;
	public void handleRequest(){
		hiService.sayHi();
		hiService.justWantToSayHi();
	}

	
}  

 执行main方法

 

 

从结果可以看到对hiService的2个方法都进行了拦截

 

开始分析源码 

 

围绕这三点开始入手,从aopMainTest类开始,类中有@EnableAspectJAutoProxy注解,为什么用了这个注解就开启了aop的大门? 点开注解发现@Import(AspectJAutoProxyRegistrar.class)

 

 

Spring框架自身就是这么使用AspectJAutoProxyRegistrar 的,如注解类@EnableAspectJAutoProxy定义所示,最终@EnableAspectJAutoProxy再应用到某个配置类上 :

AspectJAutoProxyRegistrar有一个方法registerBeanDefinitions,该方法是有2个参数AnnotationMetadata注解的相关信息,BeanDefinitionRegistry向SpringIOC容器注册的BeanDefinition的,方法作用向Spring容器注册AOP相关的服务的注册,从调用栈发现 是从容器初始化开始的

 

2、横切逻辑的加载通过调用栈发现从getBean方法开始 SpringAOP横切逻辑加载是从这开始的 CreateBean -> postProcessBeforeInstantiation

 

 

先从缓存当中获取beanName,advisedBeans保存了所有已经做过动态代理的Bean,如果被解析过则直接返回。isInfrastructureClass(beanClass)判断是不是是否实现了Advice,Pointcut,Advisor,AopInfrastructureBean这些接口或是否是切面。shouldSkip(beanClass, beanName) 中主要有2步findCandidateAdvisors()这步 合并了注解和非注解的advisors -》buildAspectJAdvisors()从容器获取所有的bean 解析被@Aspcet标记的类 提取Aspcet类中的advisors 将结果保存加入缓存

 

 

 

 

 

 

 至此横切逻辑加载完毕

 

 

横切逻辑的织入 在AbstractAutoProxyCreator.postProcessAfterInitialization()中

 

 

 

 

posted @ 2020-11-22 19:04  凌绝顶122  阅读(140)  评论(0)    收藏  举报