spring源码分析之Aop

mac2025-09-17  36

今天读spring源码,读到aop相关内容,在此记录一下,以便以后复习和查阅。

一、spring如何实现Aop

这里简单的说下原理,spring实例化bean要经历一套完整的生命周期,在这个过程中会对要实例化的bean进行各种各样的处理,例如先new对象、进行属性注入、处理循环依赖、处理生命周期回调、实现Aop等等。这些操作实际都是通过spring的后置处理器,也就是通过BeanPostProcessor来完成的。

BeanPostProcessor的主要功能就是用来修改,对Bean做一系列处理用的。

这里我们看下源码。

注:

因为spring源码实在太深,这里就省去中间步骤,直接找到对应的类和方法

这里源主要看的spring常规情况下的AOP。还有spring循环依赖情况下的AOP,这里暂不做分析,后续补充。

 

主要就是在类AbstractAutowireCapableBeanFactory的initializeBean方法中。

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { //执行spring当中的内置处理器---xxxPostProcessor---@PostConstruct 生命周期回调和InitMethod 时 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { //执行 InitializingBean 初始化 实现InitializingBean接口时 invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { //对 对象的初始化进行干预(将userService改变成为代理对象 实现aop) wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }

我们看到一行代码,wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

 上面说的这行代码,就是用来处理aop的。点进去,继续看源码。

我们可以看到,在这遍历了被注册进来的后置处理器,调用了每个BeanPostProcessor的postProcessAfterInitialization方法。

其中有一个后置处理器的这个方法,就处理了aop.我们debug打个断点看一下。

@Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; //执行所有直接实现了BeanPostProcessor的实现类的postProcessAfterInitialization for (BeanPostProcessor processor : getBeanPostProcessors()) { //拿出所有的后置处理器,调用postProcessAfterInitialization方法 Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }

 

 

上图中红色矩形框内的后置处理器,就是用来处理实现SpringAop功能。 

接着说,那么上面的后置处理器是哪里来的呢?

 我这里才用的是注解的方式,这里用过一个注解。点进去看一下,就明白了。

 

 

 那么接着说,spring做了哪些处理呢?

 spring实现aop主要通过两种技术。

JDK动态代理Cglib动态代理 

 

JDK动态代理就不多说了,这里模拟下spring采用CGlib动态代理。 

因为之前说到了,spring是通过后置处理器即实现BeanPostProcessor,调用applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)。在里面实现了aop.

我们也采用这样的思路。

代码测试:

package com.evan.config; import com.evan.processor.CustomAopBeanPostProcessor; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; //配置类 @ComponentScan("com.evan") @Configuration @Import(CustomAopBeanPostProcessor.class) public class MyConfig { } package com.evan.service; import org.springframework.stereotype.Component; /** * @ClassName UserService * @Description * @Author EvanWang * @Version 1.0.0 * @Date 2019/11/1 12:09 */ @Component public class UserService { public void testAop(){ System.out.println("---------logic code--------"); } public UserService() { System.out.println("start user"); } }

 

package com.evan.proxy; import com.evan.service.UserService; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * @ClassName CglibUtil * @Description 用来产生代理对象的util * @Author EvanWang * @Version 1.0.0 * @Date 2019/11/1 14:38 */ public class CglibUtil { public static Object getProxy() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserService.class); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("--------cglib aop----------"); Object result = methodProxy.invokeSuper(o, objects); return result; } }); Object o = enhancer.create(); return o; } }

 

package com.evan.processor; import com.evan.proxy.CglibUtil; import com.evan.service.UserService; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; /** * @ClassName CustomAopBeanPostProcessor * @Description 我们自定义的后置处理器 * @Author EvanWang * @Version 1.0.0 * @Date 2019/11/1 14:36 */ //aop核心的部分,就是后置处理器BeanPostProcessor public class CustomAopBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof UserService) { bean = CglibUtil.getProxy(); } return bean; } }

 

package com.evan.test; import com.evan.config.MyConfig; import com.evan.service.UserService; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class AopTest { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class); ac.getBean(UserService.class).testAop(); } }

 通过上面的一系列模拟,我们拿到的bean就已经是一个代理bean,即实现了Aop增强的bean。

运行结果:我们可以看到,在初始化的时候打印了一次,start user.

然后在创建代理对象时候,通过继承默认调用父类的午餐构造,又打印了一遍start user.

然后接着实现了代理,最后打印代码逻辑。至此,我们模拟的spring aop就完成了。

start user start user --------cglib aop---------- ---------logic code--------

 

二、使用spring AOP

AOP的应用详细介绍,请参考我的另一篇文章:Spring应用之AOP的使用和总结

我更倾向于,注解的使用方法,这些写一个小的demo.

 

首先引入依赖。我这里用的是gradle。maven类似,只要引入相对应的依赖就可以了。

compile(project(":spring-context")) compile(project(":spring-aop")) compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.9.4'

代码: 

package com.evan.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @ComponentScan("com.evan") @Configuration @EnableAspectJAutoProxy public class MyConfig { }

 

package com.evan.service; import org.springframework.stereotype.Component; /** * @ClassName UserService * @Description * @Author EvanWang * @Version 1.0.0 * @Date 2019/11/1 12:09 */ @Component public class UserService { public void testAop(){ System.out.println("---------logic code--------"); } public void testAop2(){ System.out.println("--------logic code---------2"); } public UserService() { System.out.println("start user"); } }

 

package com.evan.aop; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * @ClassName NotVeryUsefulAspect * @Description * @Author EvanWang * @Version 1.0.0 * @Date 2019/11/1 15:01 */ @Component @Aspect public class NotVeryUsefulAspect { //切点 @Pointcut("within(com.evan.service.UserService)") private void pointCutWithin() { } //前置通知 @Before("pointCutWithin()") public void doAccessCheck() { System.out.println("Permission verification..."); } //后置通知 @After("pointCutWithin()") public void doLog() { System.out.println("Output log..."); } }

 

package com.evan.test; import com.evan.config.MyConfig; import com.evan.service.UserService; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class AopTest { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class); ac.getBean(UserService.class).testAop(); ac.getBean(UserService.class).testAop2(); } }

运行结果: 

start user Permission verification... ---------logic code-------- Output log... Permission verification... --------logic code---------2 Output log...

 

好的关于springAOP就介绍到这里,还有很多不足。欢迎大家多提意见,以及和我讨论spring的相关技术。: )

 

 

 

 

最新回复(0)