Spring源码核心剖析 | 京东云技术团队

前言

SpringAOP作为Spring最核心的能力之一,其重要性不言而喻。然后需要知道的是AOP并不只是Spring特有的功能,而是一种思想,一种通用的功能。而SpringAOP只是在AOP的基础上将能力集成到SpringIOC中,使其作为bean的一种,从而我们能够很方便的进行使用。

一、SpringAOP的使用方式

1.1 使用场景

当我们在日常业务开发中,例如有些功能模块是通用的(日志、权限等),或者我们需要在某些功能前后去做一些增强,例如在某些方法执行后发送一条mq消息等。

如果我们将这些通用模块代码与业务代码放在一块,那么每个业务代码都要写这些通用模块,维护成本与耦合情况都十分严重。

因此,我们可以将此模块抽象出来,就有了”切面“的概念。

1.2 常用方式

AOP的使用方式相对比较简单,首先我们需要完成业务代码

1@Service 2public class AopDemo implements AopInterface{ 3 4 public Student start(String name) { 5 System.out.println("执行业务逻辑代码....."); 6 return new Student(name); 7 } 8 9}

业务逻辑比较简单,接收一个name参数。

接下来我们需要创建其对应的切面

1//将该切面加入spring容器 2@Service 3//声明该类为一个切面 4@Aspect 5class AopAspect { 6 7 //声明要进行代理的方法 8 @Pointcut("execution(* com.example.demo.aop.AopInterface.start(..))") 9 public void startAspect() { 10 } 11 12 //在方法执行之前的逻辑 13 @Before(value = "startAspect()") 14 public void beforeAspect() { 15 System.out.println("业务逻辑前代码....."); 16 } 17 18 //在方法执行之后的逻辑 19 @After(value = "startAspect()") 20 public void afterAspect() { 21 System.out.println("业务逻辑后代码....."); 22 } 23 24 //围绕方法前后的逻辑 25 @Around("startAspect()") 26 public Object aroundAspect(ProceedingJoinPoint point) throws Throwable { 27 Object[] requestParams = point.getArgs(); 28 String name = requestParams[0].toString(); 29 System.out.println("传入参数:" + name); 30 requestParams[0] = "bob"; 31 return point.proceed(requestParams); 32 } 33 34}

可以看到,首先需要我们指明要代理的对象及方法,然后根据需要选择不同的注解即可实现代理对象。

1传入参数:tom 2业务逻辑前代码..... 3执行业务逻辑代码..... 4业务逻辑后代码.....

二、SpringAOP源码解析

2.1 被代理对象的开始initializeBean

根据上面的使用情况,我们知道只需要声明对应的注解即可,不需要其他额外的配置,然后我们获得的bean对象就已经是被代理的了,那么我们可以推断代理对象的过程一定是发生在bean创建的过程的。

我们回顾一下创建bean的流程

  1. 实例化bean
  2. 装配属性
  3. 初始化bean

只有第三步初始化bean的时候才会有机会进行代理。

找到对应的代码位置:

1protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { 2 Object wrappedBean = bean; 3 if (mbd == null || !mbd.isSynthetic()) { 4 //前置处理器 5 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); 6 } 7 //... 8 try { 9 //对象的初始化方法 10 invokeInitMethods(beanName, wrappedBean, mbd); 11 } 12 if (mbd == null || !mbd.isSynthetic()) { 13 //后置处理器,AOP开始的地方 14 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); 15 } 16 17 return wrappedBean; 18}

2.2 后置处理器applyBeanPostProcessorsAfterInitialization

后置处理器会执行那些实现了后置处理器接口的代码:

1public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) 2 throws BeansException { 3 4 Object result = existingBean; 5 //获取所有的后置处理器 6 for (BeanPostProcessor processor : getBeanPostProcessors()) { 7 //实现其要执行的方法 8 Object current = processor.postProcessAfterInitialization(result, beanName); 9 if (current == null) { 10 return result; 11 } 12 result = current; 13 } 14 return result; 15}

而AOP的后置处理器就是其中的一个: AbstractAutoProxyCreator

其对应的方法为(以下代码不为同一个类,而是对应的执行顺序):

1public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { 2 if (bean != null) { 3 Object cacheKey = getCacheKey(bean.getClass(), beanName); 4 if (this.earlyProxyReferences.remove(cacheKey) != bean) { 5 //执行到下面方法 6 return wrapIfNecessary(bean, beanName, cacheKey); 7 } 8 } 9 return bean; 10} 11 12protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { 13 // Create proxy if we have advice. 14 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); 15 if (specificInterceptors != DO_NOT_PROXY) { 16 this.advisedBeans.put(cacheKey, Boolean.TRUE); 17 //创建代理对象 18 Object proxy = createProxy( 19 bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); 20 this.proxyTypes.put(cacheKey, proxy.getClass()); 21 return proxy; 22 } 23 24 this.advisedBeans.put(cacheKey, Boolean.FALSE); 25 return bean; 26} 27 28protected Object createProxy(Class beanClass, @Nullable String beanName, 29 @Nullable Object[] specificInterceptors, TargetSource targetSource) { 30 31 //获取advisors 32 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); 33 proxyFactory.addAdvisors(advisors); 34 proxyFactory.setTargetSource(targetSource); 35 customizeProxyFactory(proxyFactory); 36 37 proxyFactory.setFrozen(this.freezeProxy); 38 if (advisorsPreFiltered()) { 39 proxyFactory.setPreFiltered(true); 40 } 41 42 // Use original ClassLoader if bean class not locally loaded in overriding class loader 43 ClassLoader classLoader = getProxyClassLoader(); 44 if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) { 45 classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader(); 46 } 47 //通过代理工厂创建代理对象 48 return proxyFactory.getProxy(classLoader); 49} 50 51public Object getProxy(@Nullable ClassLoader classLoader) { 52 //首先获取对应的代理 53 return createAopProxy().getProxy(classLoader); 54} 55 56//该方法根据要被代理的类选择使用jdk代理还是cglib代理 57public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { 58 if (!NativeDetector.inNativeImage() && 59 (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) { 60 Class targetClass = config.getTargetClass(); 61 //如果被代理的类是一个接口则使用jdk代理 62 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) { 63 return new JdkDynamicAopProxy(config); 64 } 65 //否则使用cglib代理 66 return new ObjenesisCglibAopProxy(config); 67 } 68 else { 69 //根据配置选择强制使用jdk代理 70 return new JdkDynamicAopProxy(config); 71 } 72}

我们知道,代理方式有jdk动态代理与cglib动态代理两种方式,而我们一个bean使用那种代理方式则由上述的方法决定。

至此,我们已经确定了使用那种代理方式获取代理对象。

2.3 获取代理对象

从上文中,我们已经确定了选用何种方式构建代理对象。接下来就是通过不同的方式是如何获取代理对象的。

看懂本章需要实现了解jdk动态代理或者cglib动态代理的方式。

2.3.1 JDK代理

首先在获取代理对象时选择 JdkDynamicAopProxy

1public Object getProxy(@Nullable ClassLoader classLoader) { 2 if (logger.isTraceEnabled()) { 3 logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); 4 } 5 //这里通过反射创建代理对象 6 return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this); 7}

当被代理对象执行被代理的方法时,会进入到此方法。(jdk动态代理的概念)

JDK通过反射创建对象,效率上来说相对低一些。

1public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 2 3 try { 4 // 获取被代理对象的所有切入点 5 List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 6 7 // 如果调用链路为空说明没有需要执行的切入点,直接执行对应的方法即可 8 if (chain.isEmpty()) { 9 // We can skip creating a MethodInvocation: just invoke the target directly 10 // Note that the final invoker must be an InvokerInterceptor so we know it does 11 // nothing but a reflective operation on the target, and no hot swapping or fancy proxying. 12 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); 13 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); 14 } 15 else { 16 // 如果有切入点的话则按照切入点顺序开始执行 17 MethodInvocation invocation = 18 new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); 19 // Proceed to the joinpoint through the interceptor chain. 20 retVal = invocation.proceed(); 21 } 22 23 return retVal; 24 } 25}

invocation.proceed();这个方法就是通过递归的方式执行所有的调用链路。

1public Object proceed() throws Throwable { 2 // We start with an index of -1 and increment early. 3 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { 4 return invokeJoinpoint(); 5 } 6 7 Object interceptorOrInterceptionAdvice = 8 this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); 9 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { 10 InterceptorAndDynamicMethodMatcher dm = 11 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; 12 Class targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); 13 if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { 14 return dm.interceptor.invoke(this); 15 } 16 else { 17 // 继续执行 18 return proceed(); 19 } 20 } 21 else { 22 // 如果调用链路还持续的话,下一个方法仍会调用proceed() 23 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); 24 } 25}

2.3.2 cglib代理

1public Object getProxy(@Nullable ClassLoader classLoader) { 2 3 try { 4 //配置CGLIB Enhancer... 5 Enhancer enhancer = createEnhancer(); 6 if (classLoader != null) { 7 enhancer.setClassLoader(classLoader); 8 if (classLoader instanceof SmartClassLoader && 9 ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { 10 enhancer.setUseCache(false); 11 } 12 } 13 enhancer.setSuperclass(proxySuperClass); 14 enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); 15 enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); 16 enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader)); 17 18 //1.获取回调函数,对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法 19 Callback[] callbacks = getCallbacks(rootClass); 20 Class[] types = new Class[callbacks.length]; 21 for (int x = 0; x < types.length; x++) { 22 types[x] = callbacks[x].getClass(); 23 } 24 // fixedInterceptorMap only populated at this point, after getCallbacks call above 25 enhancer.setCallbackFilter(new ProxyCallbackFilter( 26 this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); 27 enhancer.setCallbackTypes(types); 28 29 //2.创建代理对象 30 return createProxyClassAndInstance(enhancer, callbacks); 31 } 32 catch (CodeGenerationException | IllegalArgumentException ex) { 33 throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + 34 ": Common causes of this problem include using a final class or a non-visible class", 35 ex); 36 } 37 catch (Throwable ex) { 38 // TargetSource.getTarget() failed 39 throw new AopConfigException("Unexpected AOP exception", ex); 40 } 41}

可以看到我们在创建代理对象前会先获取代理对象的所有回调函数:

首先可以看到我们一共有7个回调方法,其中第一个为AOP相关的方法,其他的为spring相关。

在第一个对调对象中持有的 advised 对象中有 advisors 属性,就是对应我们的代理类中四个切片,@Before等等。

然后我们看一下 createProxyClassAndInstance()都做了什么。

1//CglibAopProxy类的创建代理对象方法 2protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { 3 enhancer.setInterceptDuringConstruction(false); 4 enhancer.setCallbacks(callbacks); 5 return (this.constructorArgs != null && this.constructorArgTypes != null ? 6 enhancer.create(this.constructorArgTypes, this.constructorArgs) : 7 enhancer.create()); 8} 9 10//ObjenesisCglibAopProxy继承了CglibAopProxy类,并覆写了其方法 11protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { 12 Class proxyClass = enhancer.createClass(); 13 Object proxyInstance = null; 14 15 //1.尝试使用objenesis创建对象 16 if (objenesis.isWorthTrying()) { 17 try { 18 proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache()); 19 } 20 catch (Throwable ex) { 21 logger.debug("Unable to instantiate proxy using Objenesis, " + 22 "falling back to regular proxy construction", ex); 23 } 24 } 25 26 //2.根据commit的提交记录发现,objenesis有可能创建对象失败,如果失败的话则选用放射的方式创建对象 27 if (proxyInstance == null) { 28 // Regular instantiation via default constructor... 29 try { 30 Constructor ctor = (this.constructorArgs != null ? 31 proxyClass.getDeclaredConstructor(this.constructorArgTypes) : 32 proxyClass.getDeclaredConstructor()); 33 ReflectionUtils.makeAccessible(ctor); 34 proxyInstance = (this.constructorArgs != null ? 35 ctor.newInstance(this.constructorArgs) : ctor.newInstance()); 36 } 37 catch (Throwable ex) { 38 throw new AopConfigException("Unable to instantiate proxy using Objenesis, " + 39 "and regular proxy instantiation via default constructor fails as well", ex); 40 } 41 } 42 43 // 44 ((Factory) proxyInstance).setCallbacks(callbacks); 45 return proxyInstance; 46 }

2.3.3 cglib

此处有个遇到的问题,当我在debug的时候,发现怎么都进不去 createProxyClassAndInstance(),百思不得其解,然后看到IDEA旁边有一个向下的箭头,代表该方法可能其子类被覆写了。然后在其子类处打断点果然发现是其子类的实现。

此处在2.2中也可看到:

可以看到返回的是其子类的对象,而不是CglibAopProxy本身的对象。

作者:京东科技 韩国凯

来源:京东云开发者社区

点赞
收藏

评论区

加载中...

相关推荐

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

spring核心思想:IOC(控制反转)、DI(依赖注入)和AOP(面向切面编程)

Spring有三大核心思想,分别是控制反转(IOC,InversionOfController),依赖注入(DI,DependencyInjection)和面向切面编程(AOP,AspectOrientedProgramming)。控制反转(IOC,InversionOfController)控制反转不是什么技术,而是一种设计思

Spring源码核心剖析

SpringAOP作为Spring最核心的能力之一,其重要性不言而喻。然后需要知道的是AOP并不只是Spring特有的功能,而是一种思想,一种通用的功能。而SpringAOP只是在AOP的基础上将能力集成到SpringIOC中,使其作为bean的一种,从而我们能够很方便的进行使用。

Spring Aspect Oriented Programming

  本文是一篇SpringAOP的基础知识分析文章,其中不牵扯源码分析,只包含AOP中重要概念的讲解,分析,以及SpringAOP的用法。    Spring从2.0版本引入了更加简单却强大的基于xml和AspectJ注解的面向切面的编程方式。在深入了解如何用Spring进行面向切面的编程前,我们先了解AOP中的几个重要的基本概念,这几个概念

Spring简介,搭建Spring环境——轻量级容器框架(一)

Spring是什么?      Spring是一个集成了许多第三方框架的大杂烩,其核心技术是IOC(控制反转,也称依赖注入)和AOP(面向切面编程),所以spring既是一个IoC容器,也是一个AOP框架。知道了什么是Spring是学习的开端,下面说一下为什么使用Spring。为什么使用Spring?