从Spring源码探究AOP代码织入的过程
随着不断地使用Spring,以及后续的Boot、cloud,不断的体会到这个拯救Java的生态体系的强大,也使我对于这个框架有了极大的好奇心,以至于产生了我为什么不能写一个这样的框架的思考。
通过自学及参考谭勇德(Tom)老师的《Spring 5核心原理于30个类手写实战》这本书,记录此系列博客 。
从Spring源码探究IOC初始化流程
从Spring源码探究DI属性注入流程
愿每个想探究Spring原理的人,学习道路一帆风顺
所谓AOP
AOP是OOP的延续,是Aspect Oriented Programming 的缩写,意思是面向切面编程。
可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。我们现在做的一些非业务,如︰日志、事务、安全等都会写在业务代码中(也即是说,这些非业务类横切于业务类),但这些代码往往是重复,复制今一粘贴式的代码会给程序的维护带来不便,AOP就实现了把这些业务需求与系统需求分开来做。这种解决的方式也称代理机制。
AOP的相关概念:
- 切面( Aspect )
官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”。“切面”在ApplicationContext 中aop:aspect来配置。
连接点 (Joinpoint ):程序执行过程中的某一行为,例如,MemberService .get的调用或者MemberService .delete抛出异常等行为。 - 通知( Advice )
“切面”对于某个“连接点”所产生的动作。其中,一个“切面”可以包含多个“Advice". - 切入点( Pointcut )
匹配连接点的断言,在AOP中通知和一个切入点表达式关联。切面中的所有通知所关注的连接点,都由切入点表达式来决定。 - 目标对象(Target Object )
被一个或者多个切面所通知的对象。例如,AServcielmpl和BServicelmpl ,当然在实际运行时,SpringAOP采用代理实现,实际AOP操作的是TargetObject的代理对象。 - 代理( AOP Proxy )
在Spring AOP中有两种代理方式,JDK动态代理和CGLib代理。默认情况下,TargetObject 实现了接口时,则采用JDK动态代理;反之,采用CGLib代理。强制使用CGLib代理需要将aop:config的 proxy-target-class属性设为true。
通知(Advice)类型:
- 前置通知( Before Advice )
在某连接点( JoinPoint )之前执行的通知,但这个通知不能阻止连接点前的执行。ApplicationContext中在aop:aspect里面使用aop:before元素进行声明。例如,TestAspect 中的doBefore方法。 - 后置通知( After Advice )
当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。ApplicationContext 中在aop:aspect里面使用aop:after元素进行声明。例如,ServiceAspect 中的returnAfter方法,所以Teser中调用UserService.delete抛出异常时,returnAfter方法仍然执行。 - 返回后通知( After Return Advice )
在某连接点正常完成后执行的通知,不包括抛出异常的情况。ApplicationContext 中在aop:aspect里面使用元素进行声明。 - 环绕通知(Around Advice )
包围一个连接点的通知,类似Web中Servlet 规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。ApplicationContext中在aop:aspect里面使用aop:around元素进行声明。例如,ServiceAspect中的around方法。 - 异常通知(After Throwing Advice )
在方法抛出异常退出时执行的通知。ApplicationContext中在aop:aspect里面使用aop:after-throwing元素进行声明。例如,ServiceAspect 中的 returnThrow方法。
注:可以将多个通知应用到一个目标对象上,即可以将多个切面织入到同一目标对象。
使用Spring AOP可以基于两种方式,一种是比较方便和强大的注解方式,另一种则是中规中矩的xml配置方式。
学习Spring AOP有两个难点,第一点在于理解AOP的理念和相关概念,第二点在于灵活掌握和使用切入点表达式。概念的理解通常不在一朝一夕,慢慢浸泡的时间长了,自然就明白了。
话不多说,进入源码分析:
1 寻找入口
Spring的 AOP是通过接入BeanPostProcessor后置处理器开始的,它是Spring lOC容器经常使用到的一个特性,这个Bean后置处理器是一个监听器,可以监听容器触发的Bean声明周期事件。后置处理器向容器注册以后,容器中管理的Bean就具备了接收IOC容器事件回调的能力。
BeanPostProcessor的使用非常简单,只需要提供一个实现接口BeanPostProcessor的实现类,然后在Bean 的配置文件中设置即可。
1.1 BeanPostProcessor源码
public interface BeanPostProcessor {/*** Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}* or a custom init-method). The bean will already be populated with property values.* The returned bean instance may be a wrapper around the original.* <p>The default implementation returns the given {@code bean} as-is.* @param bean the new bean instance* @param beanName the name of the bean* @return the bean instance to use, either the original or a wrapped one;* if {@code null}, no subsequent BeanPostProcessors will be invoked* @throws org.springframework.beans.BeansException in case of errors* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet*///为在Bean的初始化前提供回调入口@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}/*** Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}* or a custom init-method). The bean will already be populated with property values.* The returned bean instance may be a wrapper around the original.* <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean* instance and the objects created by the FactoryBean (as of Spring 2.0). The* post-processor can decide whether to apply to either the FactoryBean or created* objects or both through corresponding {@code bean instanceof FactoryBean} checks.* <p>This callback will also be invoked after a short-circuiting triggered by a* {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,* in contrast to all other BeanPostProcessor callbacks.* <p>The default implementation returns the given {@code bean} as-is.* @param bean the new bean instance* @param beanName the name of the bean* @return the bean instance to use, either the original or a wrapped one;* if {@code null}, no subsequent BeanPostProcessors will be invoked* @throws org.springframework.beans.BeansException in case of errors* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet* @see org.springframework.beans.factory.FactoryBean*///为在Bean的初始化之后提供回调入口@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}}
这两个回调的入口都是和容器管理的Bean的生命周期事件紧密相关,可以为用户提供在Spring lOC容器初始化 Bean过程中自定义的处理操作。
1.2 AbstractAutowireCapableBeanFactory类对容器生成的Bean添加后置处理器
BeanPostProcessor后置处理器的调用发生在Spring lOC容器完成对Bean实例对象的创建和属性的依赖注入完成之后在对Spring依赖注入的源码分析过程中我们知道当应用程序第一次调用getBean()方法(lazy-init预实例化除外)向Spring lOC容器索取指定Bean时触发Spring lOC容器创建Bean实例对象并进行依赖注入的过程,其中真正实现创建Bean对象并进行依赖注入的方法是AbstractAutowireCapableBeanFactory类的doCreateBean()方法,主要源码如下︰
//真正创建Bean的方法protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {//创建Bean的实例对象//···无关代码省略//(在IOC中分析过),这里只分析AOP部分Object exposedObject = bean;try {//将Bean属性进行依赖注入populateBean(beanName, mbd, instanceWrapper);//在对Bean实例对象生成和依赖注入完成以后,开始对Bean实例对象//进行初始化,为Bean实例对象应用BeanPostProcessor后置处理器exposedObject = initializeBean(beanName, exposedObject, mbd);//注意这个方法<<<<<<<<}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}//···无关代码省略//(在IOC中分析过),这里只分析AOP部分//为应用返回所需要的实例对象return exposedObject;}
从上面的代码中我们知道,为Bean实例对象添加BeanPostProcessor后置处理器的入口的是initializeBean(方法。
1.3 initializeBean()方法为容器产生的Bean实例对象添加BeanPostProcessor后置处理器
同样在AbstractAutowireCapableBeanFactory类中,initializeBean()方法实现为容器创建的Bean实例对象添加BeanPostProcessor后置处理器,源码如下:
//初始容器创建的Bean实例对象,为其添加BeanPostProcessor后置处理器protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {//JDK的安全机制验证权限if (System.getSecurityManager() != null) {//实现PrivilegedAction接口的匿名内部类AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {//为Bean实例对象包装相关属性,如名称,类加载器,所属容器等信息invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;//对BeanPostProcessor后置处理器的postProcessBeforeInitialization//回调方法的调用,为Bean实例初始化前做一些处理if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}//调用Bean实例对象初始化的方法,这个初始化方法是在Spring Bean定义配置//文件中通过init-method属性指定的try {invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}//对BeanPostProcessor后置处理器的postProcessAfterInitialization//回调方法的调用,为Bean实例初始化之后做一些处理if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}@Override//调用BeanPostProcessor后置处理器实例对象初始化之后的处理方法public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;//遍历容器为所创建的Bean添加的所有BeanPostProcessor后置处理器for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {//调用Bean实例所有的后置处理中的初始化后处理方法,为Bean实例对象在//初始化之后做一些自定义的处理操作Object current = beanProcessor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;}
BeanPostProcessor是一个接口,其初始化前的操作方法和初始化后的操作方法均委托其实现子类来实现,在Spring 中,BeanPostProcessor的实现子类非常的多,分别完成不同的操作,如:AOP面向切面编程的注册通知适配器、Bean对象的数据校验、Bean继承属性、方法的合并等等,我们以最简单的AOP切面织入来简单了解其主要的功能。下面我们来分析其中一个创建AOP代理对象的子类AbstractAutoProxyCreator类。该类重写了postProcessAfterInitialization()方法。
2 选择代理策略
进入postProcessAfterlnitialization()方法,我们发现调到了一个非常核心的方法wraplfNecessary( ),其源码如下:
@Overridepublic Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (!this.earlyProxyReferences.contains(cacheKey)) {return wrapIfNecessary(bean, beanName, cacheKey);//就是这个方法<<<<<<<<}}return bean;}protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}// 判断是否不应该代理这个beanif (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}/** 判断是否是一些InfrastructureClass或者是否应该跳过这个bean。* 所谓InfrastructureClass就是指Advice/PointCut/Advisor等接口的实现类。* shouldSkip默认实现为返回false,由于是protected方法,子类可以覆盖。*/if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// 获取这个bean的advice// Create proxy if we have advice.//一会再讲,扫描所有的相关的方法(PointCut原始方法,哪些方法需要被代理)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) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);if (!proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {evaluateProxyInterfaces(beanClass, proxyFactory);}}Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);proxyFactory.addAdvisors(advisors);proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}return proxyFactory.getProxy(getProxyClassLoader());}
整个过程跟下来,我发现最终调用的是proxyFactory.getProxy)方法。到这里我们大概能够猜到proxyFactory有JDK和CGLib的,那么我们该如何选择呢?往下一路点下去,最终调用的是DefaultAopProxyFactory的createAopProxy)方法︰
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {@Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {Class<?> targetClass = config.getTargetClass();if (targetClass == null) {throw new AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation.");}if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}}/*** Determine whether the supplied {@link AdvisedSupport} has only the* {@link org.springframework.aop.SpringProxy} interface specified* (or no proxy interfaces specified at all).*/private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {Class<?>[] ifcs = config.getProxiedInterfaces();return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));}}
3 调用代理方法
我们都知道Spring提供了两种方式来生成代理,有JDKProxy和CGLib。下面我们来研究一下Spring如何使用JDK来生成代理对象,具体的生成代码放在JdkDynamicAopProxy这个类中,直接上相关代码︰
/*** 获取代理类要实现的接口,除了Advised对象中配置的,还会加上SpringProxy, Advised(opaque=false)* 检查上面得到的接口中有没有定义 equals或者hashcode的接口* 调用Proxy.newProxyInstance创建代理对象*/@Overridepublic Object getProxy(@Nullable ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());}Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);}
通过注释我们应该已经看得非常明白代理对象的生成过程,此处不再赘述。下面的问题是,代理对象生成了,那切面是如何织入的?
我们知道InvocationHandler
是 JDK动态代理的核心(其实你们不知道哈哈哈哈),生成的代理对象的方法调用都会委托到InvocationHandler.invoke(方法。而从、JdkDynamicAopProxy的源码我们可以看到这个类其实也实现了InvocationHandler,下面我们分析Spring AOP是如何织入切面的,直接上源码看invoke()方法:
@Override@Nullablepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {MethodInvocation invocation;Object oldProxy = null;boolean setProxyContext = false;TargetSource targetSource = this.advised.targetSource;Object target = null;try {//eqauls()方法,具目标对象未实现此方法if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {// The target does not implement the equals(Object) method itself.return equals(args[0]);}//hashCode()方法,具目标对象未实现此方法else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {// The target does not implement the hashCode() method itself.return hashCode();}else if (method.getDeclaringClass() == DecoratingProxy.class) {// There is only getDecoratedClass() declared -> dispatch to proxy config.return AopProxyUtils.ultimateTargetClass(this.advised);}//Advised接口或者其父接口中定义的方法,直接反射调用,不应用通知else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&method.getDeclaringClass().isAssignableFrom(Advised.class)) {// Service invocations on ProxyConfig with the proxy config...return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);}Object retVal;if (this.advised.exposeProxy) {// Make invocation available if necessary.oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}// Get as late as possible to minimize the time we "own" the target,// in case it comes from a pool.//获得目标对象的类target = targetSource.getTarget();Class<?> targetClass = (target != null ? target.getClass() : null);// Get the interception chain for this method.//获取可以应用到此方法上的Interceptor列表List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);//一会要跳回这里怕你们看懵了找不到地方先提醒一下<<<<<<<<<<<<<<<<<<<<<<<<<<<<// Check whether we have any advice. If we don't, we can fallback on direct// reflective invocation of the target, and avoid creating a MethodInvocation.//如果没有可以应用到此方法的通知(Interceptor),此直接反射调用 method.invoke(target, args)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 {// We need to create a method invocation...//创建MethodInvocationinvocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// Proceed to the joinpoint through the interceptor chain.retVal = invocation.proceed();}// Massage return value if necessary.Class<?> returnType = method.getReturnType();if (retVal != null && retVal == target &&returnType != Object.class && returnType.isInstance(proxy) &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {// Special case: it returned "this" and the return type of the method// is type-compatible. Note that we can't help if the target sets// a reference to itself in another returned object.retVal = proxy;}else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);}return retVal;}finally {if (target != null && !targetSource.isStatic()) {// Must have come from TargetSource.targetSource.releaseTarget(target);}if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}}}
主要实现思路可以简述为︰首先获取应用到此方法上的通知链( Interceptor Chain)。如果有通知,则应用通知,并执行JoinPoint ;如果没有通知,则直接反射执行JoinPoint。而这里的关键是通知链是如何获取的以及它又是如何执行的呢?
现在来逐一分析。首先,从上面的代码可以看到,通知链是通过Advised.getInterceptorsAndDynamicInterceptionAdvice()这个方法来获取的,我们来看下这个方法的实现逻辑︰
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {MethodCacheKey cacheKey = new MethodCacheKey(method);// 从缓存中获取List<Object> cached = this.methodCache.get(cacheKey);// 缓存未命中,则进行下一步处理if (cached == null) {// 获取所有的拦截器cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);// 存入缓存this.methodCache.put(cacheKey, cached);}return cached;}
通过上面的源码我们可以看到,实际获取通知的实现逻辑其实是由AdvisorChainFactory 的getInterceptorsAndDynamicInterceptionAdvice()方法来完成的,且获取到的结果会被缓存。下面来分析getlnterceptorsAndDynamicInterceptionAdvice()方法的实现∶
/*** 从提供的配置实例config中获取advisor列表,遍历处理这些advisor.如果是IntroductionAdvisor,* 则判断此Advisor能否应用到目标类targetClass上.如果是PointcutAdvisor,则判断* 此Advisor能否应用到目标方法method上.将满足条件的Advisor通过AdvisorAdaptor转化成Interceptor列表返回.*/@Overridepublic List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {// This is somewhat tricky... We have to process introductions first,// but we need to preserve order in the ultimate list.List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());//查看是否包含IntroductionAdvisorboolean hasIntroductions = hasMatchingIntroductions(config, actualClass);//这里实际上注册一系列AdvisorAdapter,用于将Advisor转化成MethodInterceptorAdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();for (Advisor advisor : config.getAdvisors()) {if (advisor instanceof PointcutAdvisor) {// Add it conditionally.PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {//这个地方这两个方法的位置可以互换下//将Advisor转化成InterceptorMethodInterceptor[] interceptors = registry.getInterceptors(advisor);//检查当前advisor的pointcut是否可以匹配当前方法MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {if (mm.isRuntime()) {// Creating a new object instance in the getInterceptors() method// isn't a problem as we normally cache created chains.for (MethodInterceptor interceptor : interceptors) {interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));}}else {interceptorList.addAll(Arrays.asList(interceptors));}}}}else if (advisor instanceof IntroductionAdvisor) {IntroductionAdvisor ia = (IntroductionAdvisor) advisor;if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {Interceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}}else {Interceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}}return interceptorList;}
这个方法执行完成后,Advised中配置能够应用到连接点(JoinPoint)或者目标类(Target Object )的Advisor全部被转化成了MethodInterceptor,接下来我们再看下得到的拦截器链是怎么起作用的。
往上跳,跳回至invoke方法的提醒的地方:
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 {// We need to create a method invocation...//创建MethodInvocationinvocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// Proceed to the joinpoint through the interceptor chain.retVal = invocation.proceed();}
从这段代码可以看出,如果得到的拦截器链为空,则直接反射调用目标方法,否则创建MethodInvocation,调用其proceed()方法,触发拦截器链的执行,来看下具体代码:
@Override@Nullablepublic Object proceed() throws Throwable {// We start with an index of -1 and increment early.//如果Interceptor执行完了,则执行joinPointif (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();//这里就是反射调用,下面看这里}Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);//如果要动态匹配joinPointif (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// Evaluate dynamic method matcher here: static part will already have// been evaluated and found to match.InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;//动态匹配:运行时参数是否满足匹配条件if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {return dm.interceptor.invoke(this);}else {// Dynamic matching failed.// Skip this interceptor and invoke the next in the chain.//动态匹配失败时,略过当前Intercetpor,调用下一个Interceptorreturn proceed();}}else {// It's an interceptor, so we just invoke it: The pointcut will have// been evaluated statically before this object was constructed.//执行当前Intercetporreturn ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}
至此,通知链就完美地形成了。我们再往下来看invokeJoinpointUsingReflection()方法,其实就是反
射调用︰
protected Object invokeJoinpoint() throws Throwable {return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);}@Nullablepublic static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)throws Throwable {// Use reflection to invoke the method.try {ReflectionUtils.makeAccessible(method);return method.invoke(target, args);}catch (InvocationTargetException ex) {// Invoked method threw a checked exception.// We must rethrow it. The client won't see the interceptor.throw ex.getTargetException();}catch (IllegalArgumentException ex) {throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +method + "] on target [" + target + "]", ex);}catch (IllegalAccessException ex) {throw new AopInvocationException("Could not access method [" + method + "]", ex);}}
Spring AOP源码就分析到这儿,相信小伙伴们应该有了基本思路
从Spring源码探究AOP代码织入的过程相关推荐
- 从Spring源码探究DI属性注入流程
随着不断地使用Spring,以及后续的Boot.cloud,不断的体会到这个拯救Java的生态体系的强大,也使我对于这个框架有了极大的好奇心,以至于产生了我为什么不能写一个这样的框架的思考. 通过自学 ...
- 【Spring源码】AOP切面源码
[Spring源码]AOP切面源码 关键词 后置处理器BeanPostProcessor后置方法:applyBeanPostProcessorsAfterInitialization() 切面后置处理 ...
- Spring源码阅读之bean对象的创建过程
Spring源码阅读之bean对象的创建过程 Spring是通过IOC容器来管理对象的,该容器不仅仅只是帮我们创建了对象那么简单,它负责了对象的整个生命周期-创建.装配.销毁.这种方式成为控制反转 ...
- Spring源码解析:自定义标签的解析过程
2019独角兽企业重金招聘Python工程师标准>>> spring version : 4.3.x Spring 中的标签分为默认标签和自定义标签两类,上一篇我们探究了默认标签的解 ...
- spring源码阅读--aop实现原理分析
aop实现原理简介 首先我们都知道aop的基本原理就是动态代理思想,在设计模式之代理模式中有介绍过这两种动态代理的使用与基本原理,再次不再叙述. 这里分析的是,在spring中是如何基于动态代理的思想 ...
- Spring源码:AOP转文
Spring源码分析-深入浅出AOP(图文分析) https://blog.csdn.net/c_unclezhang/article/details/78769426 Spring中AOP的配置从1 ...
- Spring源码——动态AOP实现流程
前言 最近回顾了一下Spring源码,准备用思维导图的方式简单的将整个源码内容的流程展示出来,思维导图.图片等文件更新在https://github.com/MrSorrow/spring-frame ...
- 从Spring源码探究IOC初始化流程
随着不断地使用Spring,以及后续的Boot.cloud,不断的体会到这个拯救Java的生态体系的强大,也使我对于这个框架有了极大的好奇心,以至于产生了我为什么不能写一个这样的框架的思考. 通过自学 ...
- 专治不会看源码的毛病--spring源码解析AOP篇(2017版)
昨天有个大牛说我啰嗦,眼光比较细碎,看不到重点.太他爷爷的有道理了!要说看人品,还是女孩子强一些.原来记得看到一个男孩子的抱怨,说怎么两人刚刚开始在一起,女孩子在心里就已经和他过完了一辈子.哥哥们,不 ...
最新文章
- java集合类学习笔记之LinkedHashMap
- 数据结构与算法笔记(十四)—— 二叉树
- Java基础提升篇:equals()方法和“==”运算符
- dedecms index_testenv.php,一招方面解决DedeCms后台反应慢
- javascript 之数据类型--01
- 笔试小结---非对称加密算法
- thymeleaf th:href url传递多参数
- apache 支持.htaccess重写url
- 一条命令扫描局域网所以IP地址和MAC地址
- 关于Raspberry Pi,Python等的6本书
- linux 子shell
- VPP 20.09版本正式发布
- 记账系统(java)
- 西安三星电子笔试面试
- 计算机室火灾隐患表现,校园安全防火知识
- 区块链开发之确定性算法bip32,bip39,bip44
- 义冢oj P5033打气球
- html怎么设置点击播放音乐,html5点击播放音乐试听按钮动画特效
- 研华板卡1742U--瞬时读值 用 instantAiCtrl1 控件
- Java-面向对象 练习题
热门文章
- matlab怎么画两个自变量的图_眼线液的画步骤图 眼线怎么画好看图解
- 互联网公司发送短信为什么通过第三方短信平台,而不是通过运营商。
- 国学大师林语堂献宝:英文学习八要诀
- qemu 规范路径_EVE-NG镜像添加技巧(以思科虚拟化产品为例)
- android什么叫服务器,Android系统中神秘的Bootloader究竟是什么
- 百度地图获取规划路径信息
- kotlin实现的简单个人账户管理APP(三) 自定义View仿支付宝的密码输入框/密码相关逻辑
- 数据库架构设计——数据库选型
- 商业智能,数据仓库,ETL,数仓调度工具informatica介绍手账(一)
- PPT中含图片太大,需压缩