您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
Spring源码核心剖析
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
Spring源码核心剖析
RyanHan
2023-06-19
IP归属:北京
6960浏览
## 前言 SpringAOP作为Spring最核心的能力之一,其重要性不言而喻。然后需要知道的是AOP并不只是Spring特有的功能,而是一种思想,一种通用的功能。而SpringAOP只是在AOP的基础上将能力集成到SpringIOC中,使其作为bean的一种,从而我们能够很方便的进行使用。 ## 一、SpringAOP的使用方式 ### 1.1 使用场景 当我们在日常业务开发中,例如有些功能模块是通用的(日志、权限等),或者我们需要在某些功能前后去做一些增强,例如在某些方法执行后发送一条mq消息等。 如果我们将这些通用模块代码与业务代码放在一块,那么每个业务代码都要写这些通用模块,维护成本与耦合情况都十分严重。 因此,我们可以将此模块抽象出来,就有了”切面“的概念。 ### 1.2 常用方式 AOP的使用方式相对比较简单,首先我们需要完成业务代码 ```java @Service public class AopDemo implements AopInterface{ public Student start(String name) { System.out.println("执行业务逻辑代码....."); return new Student(name); } } ``` 业务逻辑比较简单,接收一个name参数。 接下来我们需要创建其对应的切面 ```Java //将该切面加入spring容器 @Service //声明该类为一个切面 @Aspect class AopAspect { //声明要进行代理的方法 @Pointcut("execution(* com.example.demo.aop.AopInterface.start(..))") public void startAspect() { } //在方法执行之前的逻辑 @Before(value = "startAspect()") public void beforeAspect() { System.out.println("业务逻辑前代码....."); } //在方法执行之后的逻辑 @After(value = "startAspect()") public void afterAspect() { System.out.println("业务逻辑后代码....."); } //围绕方法前后的逻辑 @Around("startAspect()") public Object aroundAspect(ProceedingJoinPoint point) throws Throwable { Object[] requestParams = point.getArgs(); String name = requestParams[0].toString(); System.out.println("传入参数:" + name); requestParams[0] = "bob"; return point.proceed(requestParams); } } ``` 可以看到,首先需要我们指明要代理的对象及方法,然后根据需要选择不同的注解即可实现代理对象。 ``` 传入参数:tom 业务逻辑前代码..... 执行业务逻辑代码..... 业务逻辑后代码..... ``` ## 二、SpringAOP源码解析 ### 2.1 被代理对象的开始initializeBean 根据上面的使用情况,我们知道只需要声明对应的注解即可,不需要其他额外的配置,然后我们获得的bean对象就已经是被代理的了,那么我们可以推断代理对象的过程一定是发生在bean创建的过程的。 我们回顾一下创建bean的流程 1. 实例化bean 2. 装配属性 3. 初始化bean 只有第三步初始化bean的时候才会有机会进行代理。 找到对应的代码位置: ```Java protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { //前置处理器 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } //... try { //对象的初始化方法 invokeInitMethods(beanName, wrappedBean, mbd); } if (mbd == null || !mbd.isSynthetic()) { //后置处理器,AOP开始的地方 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; } ``` ### 2.2 后置处理器applyBeanPostProcessorsAfterInitialization 后置处理器会执行那些实现了后置处理器接口的代码: ```Java public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; //获取所有的后置处理器 for (BeanPostProcessor processor : getBeanPostProcessors()) { //实现其要执行的方法 Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; } ``` 而AOP的后置处理器就是其中的一个: `AbstractAutoProxyCreator` 其对应的方法为(以下代码不为同一个类,而是对应的执行顺序): ```Java public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { //执行到下面方法 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // Create proxy if we have advice. 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; } protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { //获取advisors Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } // Use original ClassLoader if bean class not locally loaded in overriding class loader ClassLoader classLoader = getProxyClassLoader(); if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) { classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader(); } //通过代理工厂创建代理对象 return proxyFactory.getProxy(classLoader); } public Object getProxy(@Nullable ClassLoader classLoader) { //首先获取对应的代理 return createAopProxy().getProxy(classLoader); } //该方法根据要被代理的类选择使用jdk代理还是cglib代理 public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (!NativeDetector.inNativeImage() && (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) { Class<?> targetClass = config.getTargetClass(); //如果被代理的类是一个接口则使用jdk代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) { return new JdkDynamicAopProxy(config); } //否则使用cglib代理 return new ObjenesisCglibAopProxy(config); } else { //根据配置选择强制使用jdk代理 return new JdkDynamicAopProxy(config); } } ``` 我们知道,代理方式有jdk动态代理与cglib动态代理两种方式,而我们一个bean使用那种代理方式则由上述的方法决定。 至此,我们已经确定了使用那种**代理方式**获取代理对象。 ### 2.3 获取代理对象 从上文中,我们已经确定了选用何种方式构建代理对象。接下来就是通过不同的方式是如何获取代理对象的。 看懂本章需要实现了解jdk动态代理或者cglib动态代理的方式。 #### 2.3.1 JDK代理 首先在获取代理对象时选择 `JdkDynamicAopProxy` ```Java public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); } //这里通过反射创建代理对象 return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this); } ``` 当被代理**对象执行被代理的方法**时,会进入到此方法。(jdk动态代理的概念) JDK通过反射创建对象,效率上来说相对低一些。 ```Java public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { // 获取被代理对象的所有切入点 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // 如果调用链路为空说明没有需要执行的切入点,直接执行对应的方法即可 if (chain.isEmpty()) { // We can skip creating a MethodInvocation: just invoke the target directly // Note that the final invoker must be an InvokerInterceptor so we know it does // nothing but a reflective operation on the target, and no hot swapping or fancy proxying. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // 如果有切入点的话则按照切入点顺序开始执行 MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); } return retVal; } } ``` `invocation.proceed();`这个方法就是通过递归的方式执行所有的调用链路。 ```Java public Object proceed() throws Throwable { // We start with an index of -1 and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // 继续执行 return proceed(); } } else { // 如果调用链路还持续的话,下一个方法仍会调用proceed() return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } } ``` #### 2.3.2 cglib代理 ```Java public Object getProxy(@Nullable ClassLoader classLoader) { try { //配置CGLIB Enhancer... Enhancer enhancer = createEnhancer(); if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } enhancer.setSuperclass(proxySuperClass); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader)); //1.获取回调函数,对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法 Callback[] callbacks = getCallbacks(rootClass); Class<?>[] types = new Class<?>[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } // fixedInterceptorMap only populated at this point, after getCallbacks call above enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types); //2.创建代理对象 return createProxyClassAndInstance(enhancer, callbacks); } catch (CodeGenerationException | IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + ": Common causes of this problem include using a final class or a non-visible class", ex); } catch (Throwable ex) { // TargetSource.getTarget() failed throw new AopConfigException("Unexpected AOP exception", ex); } } ``` 可以看到我们在创建代理对象前会先获取代理对象的所有回调函数: ![image-20230310174107202](https://s2.loli.net/2023/03/10/wDRQOpAJEtscZ5q.png) 首先可以看到我们一共有7个回调方法,其中第一个为AOP相关的方法,其他的为spring相关。 在第一个对调对象中持有的 `advised`对象中有 `advisors`属性,就是对应我们的代理类中四个切片,@Before等等。 然后我们看一下 `createProxyClassAndInstance()`都做了什么。 ```Java //CglibAopProxy类的创建代理对象方法 protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { enhancer.setInterceptDuringConstruction(false); enhancer.setCallbacks(callbacks); return (this.constructorArgs != null && this.constructorArgTypes != null ? enhancer.create(this.constructorArgTypes, this.constructorArgs) : enhancer.create()); } //ObjenesisCglibAopProxy继承了CglibAopProxy类,并覆写了其方法 protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { Class<?> proxyClass = enhancer.createClass(); Object proxyInstance = null; //1.尝试使用objenesis创建对象 if (objenesis.isWorthTrying()) { try { proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache()); } catch (Throwable ex) { logger.debug("Unable to instantiate proxy using Objenesis, " + "falling back to regular proxy construction", ex); } } //2.根据commit的提交记录发现,objenesis有可能创建对象失败,如果失败的话则选用放射的方式创建对象 if (proxyInstance == null) { // Regular instantiation via default constructor... try { Constructor<?> ctor = (this.constructorArgs != null ? proxyClass.getDeclaredConstructor(this.constructorArgTypes) : proxyClass.getDeclaredConstructor()); ReflectionUtils.makeAccessible(ctor); proxyInstance = (this.constructorArgs != null ? ctor.newInstance(this.constructorArgs) : ctor.newInstance()); } catch (Throwable ex) { throw new AopConfigException("Unable to instantiate proxy using Objenesis, " + "and regular proxy instantiation via default constructor fails as well", ex); } } // ((Factory) proxyInstance).setCallbacks(callbacks); return proxyInstance; } ``` ### 2.3.3 cglib 此处有个遇到的问题,当我在debug的时候,发现怎么都进不去 `createProxyClassAndInstance()`,百思不得其解,然后看到IDEA旁边有一个向下的箭头,代表该方法可能其子类被覆写了。然后在其子类处打断点果然发现是其子类的实现。 此处在2.2中也可看到: ![image-20230310174806723](https://s2.loli.net/2023/03/10/g2i7SfVo1nvjJNI.png) 可以看到返回的是其子类的对象,而不是`CglibAopProxy`本身的对象。
上一篇:Maven进阶学习指南
下一篇:Spring竟然可以创建“重复”名称的bean?—一次项目中存在多个bean名称重复问题的排查
RyanHan
文章数
15
阅读量
52378
作者其他文章
01
三十分钟入门基础Go——Java小子版
本篇文章适用于学习过其他面向对象语言(Java、Php),但没有学过Go语言的初学者。文章主要从Go与Java功能上的对比来阐述Go语言的基础语法、面向对象编程、并发与错误四个方面。
01
Dubbo源码浅析(一)—RPC框架与Dubbo
RPC,Remote Procedure Call 即远程过程调用,与之相对的是本地服务调用,即LPC(Local Procedure Call)。
01
0源码基础学习Spring源码系列(一)——Bean注入流程
通过本文,读者可以0源码基础的初步学习spring源码,并能够举一反三从此进入源码世界的大门!
01
Dubbo源码浅析(二)—SPI机制
SPI (Service Provider Interface),是一种将服务接口与服务实现实现分离的机制,以达到解耦的目的,大大提高了项目的可拓展性。
RyanHan
文章数
15
阅读量
52378
作者其他文章
01
三十分钟入门基础Go——Java小子版
01
Dubbo源码浅析(一)—RPC框架与Dubbo
01
0源码基础学习Spring源码系列(一)——Bean注入流程
01
Dubbo源码浅析(二)—SPI机制
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号