参考书籍《Spring技术内幕》Spring AOP的实现章节书有点老,但是里面一些概念还是总结比较到位源码基于Spring-aop 5.3.22 可能和旧版本有所差异但是大体逻辑一致AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。 是一种新的模块化机制,用来描述分散在对象,类,或函数中的横切关注点,分离关注点使解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑代码中不在含义针对特定领域的代码调用,业务逻辑同特定领域问题的关系通过切面封装,维护,这样原本分散在整个应用程序中的变动可以很好地管理起来。
用人话说就是,通过切面完成特定逻辑(事务,入参出参日志等)可以和业务逻辑(crud)抽离开,便于维护定义在连接点做什么,为切面增强提供植入接口。描述Spring AOP围绕方法调而注入的切面行为
切点决定Advice通知应该作用在哪个连接点,也就是通过Poincut来定义需要增强的方法集合,这些集合可以按照一定规则来完成,这种情况下,Pointcut意味着标识方法(比如事务切面定义了事务注解方法上生效)切入点是一些列织入逻辑代码的连接点集合
整合Advice 和 Pointcut,定义应该使用哪个通知器并在哪个关注点使用它。
我们先抛弃Spring框架,利用Spring aop中存在的工具实现aop增强。

Advice接口的实现有AfterAdvice后置通知,Beforeadvice前置通知,MethodInterceptor方法拦截器可以看做是环绕通知。
/** * 服务类 */public static class Service{ public void doSomething(){ System.out.println("service doSomething"); }}/*** * 自定义的advice 环绕通知 */public static class MyAdvice implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("my advice before"); //service 方法执行 Object res = invocation.proceed(); System.out.println("my advice after"); return res; }}public static void main(String[] args) { //代理工程 用于生成代理对象 ProxyFactory proxyFactory = new ProxyFactory(); //目标对象 Service service = new Service(); //设置需要代理的对象 proxyFactory.setTarget(service); proxyFactory.addAdvice(new MyAdvice()); //生成代理对象 Service proxyService = (Service) proxyFactory.getProxy(); //代理对象执行 proxyService.doSomething();}上述代码执行结果

基于Advice,ProxyFactory成功实现了Aop代理增强

public static void advisorBased(){ //代理工程 用于生成代理对象 ProxyFactory proxyFactory = new ProxyFactory(); //目标对象 Service service = new Service(); //advisor DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(); //根据名称匹配方法的pointcut NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut(); //指定只有doSomething 才增强 pointcut.setMappedName("doSomething"); advisor.setPointcut(pointcut); advisor.setAdvice(new MyAdvice()); //设置需要代理的对象 proxyFactory.setTarget(service); proxyFactory.addAdvisor(advisor); //生成代理对象 Service proxyService = (Service) proxyFactory.getProxy(); //代理对象执行 proxyService.doSomething(); System.out.println(); proxyService.sayHello();}
最后我们发现只有名称匹配的方法才生效。
Advisor接口具备方法Advice getAdvice()来获取通知。PointcutAdvisor实现了Advisor并且新增方法Pointcut getPointcut()来获取切入点的定义。Pointcut接口定义了两个方法ClassFilter getClassFilter(),MethodMatcher getMethodMatcher()分别是对类和方法的筛选,来决定Advise是不是应该作用于当前类。

TargetSource 用于获取 AOP 调用的当前“目标”

getTargetClass可以获取被代理对象的类型,getTarget可以获取被代理对象,HotSwappableTargetSource中的swap方法可以替换掉代理对象,Spring aop常用的是SingletonTargetSource它持有了原始的被代理对象。
public Object getProxy() { return createAopProxy().getProxy();}

这里生成的AopProxy 才是负责生成代理对象的,其中spring内置了两种策略——JDK动态代理和CGLIB动态代理。
只有设置了需要代理目标类,或者说没有指定代理的接口,且代理目标类不是接口,不是lambda,不是已经被JDK动态代理后的类,那么才会使用CGLIB进行动态代理。

其中JdkDynamicAopProxy,还实现了InvocationHandler。
Jdk动态代理
生成代理对象
Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this),这里的this便是自己。
invoke
首先是对`equals`,`hashCode`的处理,目标对象声明了让目标对象执行,反之调用`JdkDynamicAopProxy`对应的方法其次是如果配置中设置了暴露代理对象,那么将其放入到`AopContext`中的`ThreadLocal`中```javaif (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true;}```然后获取当前对象的拦截器链,如果拦截器链为空 那么直接反射调用目标对象的方法。如果存在拦截器链那么new 一个`ReflectiveMethodInvocation`利用反射依次执行。Spring只支持方法拦截器`MethodInterceptor`进行代理增强,对于Advise都会适配成`MethodInterceptor`,Spring采用适配器模式,具体的适配器如下```javapublic interface AdvisorAdapter { //支持什么Advise被适配 boolean supportsAdvice(Advice advice); //适配 MethodInterceptor getInterceptor(Advisor advisor);}```自然是Spring遍历每一个Advise责任链模式依次找到`AdvisorAdapter`然后调用适配方法得到一个`MethodInterceptor`,下面是适配成的`MethodInterceptor`。CGLIB动态代理
设置CallBack
首先new 一个Enhancer设置父类为被代理对象的类型,这里会把讲Aop的逻辑转变为一个DynamicAdvisedInterceptor,equals和hashCode方法也有对应的callBack

注意这里的MethodInterceptor是org.springframework.cglib.proxy.MethodInterceptor,其中的intercept 方法的逻辑和JDK动态代理的invoke类似,都是链式调用。

ProxyFactoryBean创建代理对象的逻辑和ProxyFactory类似,但是ProxyFactoryBean是一个FactoryBean,我们可以利用这一点在bean初始化的时候生成一个代理对象


创建原型对象类似,但是不会判断之前是否创建过,直接无脑创建即可
通常我们在使用Spring Aop的时候会在启动类上加一个@EnableAspectJAutoProxy注解,这个注解@Import(AspectJAutoProxyRegistrar.class)导入了AspectJAutoProxyRegistrar,这个类实现了ImportBeanDefinitionRegistrar,Spring容器会调用其registerBeanDefinitions方法为我们注入BeanDefinition,后续会实例化一个AnnotationAwareAspectJAutoProxyCreator类型的bean,它是Spring IOC和AOP结合的关键

这其中最为关键的必然是AnnotationAwareAspectJAutoProxyCreator是一个BeanPostProcessor,从而在Spring 回调postProcessAfterInitialization对bean进行代理的增强,并且它实现了SmartInstantiationAwareBeanPostProcessor Spring容器创建bean的时候如果出现了循环依赖那么会调用到getEarlyBeanReference,在这个方法里面同样也会进行aop的增强
AbstractAutoProxyCreator 实现了SmartInstantiationAwareBeanPostProcessor是一个bean后置处理器,使用 AOP 代理包装每个符合条件的 bean,在调用 bean 本身之前委托给指定的拦截器,AOP代理发生的地方。
AbstractAdvisorAutoProxyCreator
为了每一个Bean找到合适的Advisor并且进行,如果Advisor标注了@Order或者说实现了Ordered接口那么会进行排序。
AspectJAwareAdvisorAutoProxyCreator
AbstractAdvisorAutoProxyCreator子类,对一个切面中的多个Advisor进行优先级排序
AnnotationAwareAspectJAutoProxyCreator
AspectJAwareAdvisorAutoProxyCreator的子类,会将容器中标注了@AspectJ注解的类解析成Advisor(整合Advice 和 Pointcut,定义应该使用哪个通知器并在哪个关注点使用它)
AbstractAutoProxyCreator是如何进行Aop增强的

进行AOP增强的地方其实还有postProcessBeforeInstantiation如果我们自己配置了TargetSourceCreator并且可以为当前bean生成,那么才可能发生aop,这里一般不会进行任何操作。

其中shouldSkip被AspectJAwareAdvisorAutoProxyCreator重写,如果Advisor是AspectJPointcutAdvisor并且切面名称和bean名称相同那么会跳过,这应该是我们标注@Aspect的时候需要保证这个类会被Spring加入到容器,所有需要加@Componet所以会过滤掉

findCandidateAdvisors方法会找到容器中所以的Advisor类型的bean,AnnotationAwareAspectJAutoProxyCreator进行了重写,它还会把所以标注了@Aspect注解的bean中的增强逻辑封装成Advisor
findAdvisorsThatCanApply这个方法内部逻辑基本上就是调用PointcutAdvisor获取类过滤器,方法匹配器进行匹配。
sortAdvisors 这里默认是通过@Order注解,或者Ordered接口进行排序,但是AspectJAwareAdvisorAutoProxyCreator进行了重写,因为它需要对同一个标注@Aspect切面里面的前置后置等进行排序
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); //这里的ProxyTargetClass 来自上面的copyFrom 取决于EnableAspectJAutoProxy注解的proxyTargetClass //proxyTargetClass 表示是否使用基于CGLIB子类的代理 if (!proxyFactory.isProxyTargetClass()) { //shouldProxyTargetClass 方法就是去BeanFactory中看当前bean的BeanDefinition中是否存在AutoProxy.PRESERVE_TARGET_CLASS_ATTRIBUTE=trued的attribute,当我们手动注入bean的时候可以使用这个强制让当前bean使用CGLIB增强 if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { //获取当前类中非Spring回调(InitializingBean,DisposableBean,Aware)类型的接口,且如果接口的方法大于0,那么会把接口类型加入到proxyFactory中,否则设置ProxyTargetClass(没有接口那么没办法使用JDK动态代理) evaluateProxyInterfaces(beanClass, proxyFactory); } } //主要是把上面找到的advise 适配成Advisor。调用的是advisorAdapterRegistry的wrap方法 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); //这里的targetSource是SingletonTargetSource proxyFactory.setTargetSource(targetSource); //留给子类扩展的方法 customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } //生成代理对象 return proxyFactory.getProxy(getProxyClassLoader());}这里其实和我们上面的Aop编程体验中基于Advisor类似,最后都是AopProxy创建代理对象
上面我们讲了其父类AbstractAutoProxyCreator的大体逻辑,AnnotationAwareAspectJAutoProxyCreator会将@Aspect注解类解析成Advisor,下面我们重点看下AnnotationAwareAspectJAutoProxyCreator是怎么将@Aspect注解类解析成Advisor的

这里依赖了BeanFactoryAspectJAdvisorsBuilder,它会遍历所有bean,并调用isAspect方法

然后调用ReflectiveAspectJAdvisorFactory的getAdvisors方法将其适配成多个Advisor,会遍历每一个没有标注@Pointcut的方法,然后获取@Around, @Before, @After, @AfterReturning, @AfterThrowing(如果没有那么直接返回)然后获取value中的内容包装成AspectJExpressionPointcut(AspectJ表达式pointcut),然后包装成InstantiationModelAwarePointcutAdvisorImpl在这个类中会把对应注解的方法封装成对应的AbstractAspectJAdvice的子类

调用对应方法依旧采用反射,其子类在合适的实际进行调用。