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()中


浙公网安备 33010602011771号