Auto-proxy(实现自动AOP代理)
自动代理机制的实现其实很简单,就是通过Bean的后置处理器,在创建Bean的最后一步对Bean进行代理,并将代理对象放入到容器中。
实现自动代理的核心类就是AbstractAutoProxyCreator。我们来看看它的继承关系
为了更好的体会自动代理的作用,我们对它的三个具体的实现类来进行分析,分别是
- BeanNameAutoProxyCreator
- DefaultAdvisorAutoProxyCreator
- AnnotationAwareAspectJAutoProxyCreator
BeanNameAutoProxyCreator
使用示例
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="com.dmz.spring.initalize.service.DmzService" name="dmzService"/> <bean id="aroundAdvice" class="com.dmz.spring.initalize.aop.advice.DmzAroundAdvice"/> <bean id="beforeAdvice" class="com.dmz.spring.initalize.aop.advice.DmzBeforeAdvice"/> <!--使用很简单,只要配置一个BeanNameAutoProxyCreator即可--> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" name="autoProxyCreator"> <!--使用cglib代理--> <property name="proxyTargetClass" value="true"/> <!--对所有以dmz开头的bean进行自动代理--> <property name="beanNames" value="dmz*"/> <!--添加两个通知--> <property name="interceptorNames"> <list> <value>beforeAdvice</value> <value>aroundAdvice</value> </list> </property> </bean> </beans>
public class SourceMain { public static void main(String[] args) { ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("application-init.xml"); DmzService dmzProxy = ((DmzService) cc.getBean("dmzService")); dmzProxy.testAop(); } } // 程序打印: // before invoke method [testAop],aop before logic invoked // aroundAdvice invoked // testAop invoke
DefaultAdvisorAutoProxyCreator
使用示例
在上面例子的基础上我们要修改配置文件,如下
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="com.dmz.spring.initalize.service.DmzService" name="dmzService"/> <bean id="aroundAdvice" class="com.dmz.spring.initalize.aop.advice.DmzAroundAdvice"/> <bean id="beforeAdvice" class="com.dmz.spring.initalize.aop.advice.DmzBeforeAdvice"/> <bean class="org.springframework.aop.support.DefaultPointcutAdvisor" id="dmzBeforeAdvisor"> <property name="advice" ref="beforeAdvice"/> </bean> <bean class="org.springframework.aop.support.DefaultPointcutAdvisor" id="dmzAroundAdvisor"> <property name="advice" ref="aroundAdvice"/> </bean> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" id="advisorAutoProxyCreator"> <!--这两个参数标明了我们要使用所有以dmz开头的Advisor类型的通知 这里必须配置是Advisor,不能是Advice或者interceptor, 可以看到DefaultAdvisorAutoProxyCreator跟BeanNameAutoProxyCreator的区别在于 BeanNameAutoProxyCreator需要指定要被代理的bean的名称, 而DefaultAdvisorAutoProxyCreator不需要,它会根据我们传入的Advisor 获取到需要被代理的切点 --> <property name="usePrefix" value="true"/> <property name="advisorBeanNamePrefix" value="dmz"/> <property name="proxyTargetClass" value="true"/> </bean> </beans>
测试代码就不放了,大家可以自行测试,肯定是没问题的
AnnotationAwareAspectJAutoProxyCreator
我们正常在使用AOP的时候都会在配置类上添加一个@EnableAspectJAutoProxy注解,这个注解干了什么事呢?
实际就是向容器中注册了一个AnnotationAwareAspectJAutoProxyCreator。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented // 这里导入了一个类 @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { boolean proxyTargetClass() default false; boolean exposeProxy() default false; }
通过@EnableAspectJAutoProxy导入了一个AspectJAutoProxyRegistrar,这个类会向容器中注册一个AnnotationAwareAspectJAutoProxyCreator,对应源码如下:
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 在这里完成的注册 // 最终会调用到AopUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法 // 完成AnnotationAwareAspectJAutoProxyCreator这个bd的注册 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); // 解析注解的属性 // proxyTargetClass:为true的话开启cglib代理,默认为jdk代理 // exposeProxy:是否将代理对象暴露到线程上下文中 AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy != null) { if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } }
前面已经说过了,自动代理机制实际上就是Spring在内部new了一个ProxyFactory,通过它创建了一个代理对象。对应的代码就在AbstractAutoProxyCreator中的createProxy方法内,源码如下:
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 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); } // 通过proxyFactory来创建一个代理对象 return proxyFactory.getProxy(getProxyClassLoader()); }
关于这个类的执行流程在下篇文章中我再详细介绍,接下来我们要分析的就是具体创建AOP代理的源码了。对应的核心源码就是我们之前所提到的
createAopProxy().getProxy();
这行代码分为两步,我们逐步分析
1.调用AopProxyFactory的createAopProxy()方法获取一个AopProxy对象
2.调用AopProxy对象的getProxy()方法
核心源码分析
createAopProxy方法分析
AopProxyFactory在Spring中只有一个默认的实现类,就是DefaultAopProxyFactory,它的对应的createAopProxy的是实现代码如下:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { // 就是通过AOP相关的配置信息来决定到底是使用cglib代理还是jdk代理 @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // 如果开启了优化,或者ProxyTargetClass设置为true // 或者没有提供代理类需要实现的接口,那么使用cglib代理 // 在前面分析参数的时候已经说过了 // 默认情况下Optimize都为false,也不建议设置为true,因为会进行一些侵入性的优化 // 除非你对cglib的优化非常了解,否则不建议开启 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."); } // 需要注意的是,如果需要代理的类本身就是一个接口 // 或者需要被代理的类本身就是一个通过jdk动态代理生成的类 // 那么不管如何设置都会使用jdk动态代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } // 否则都是jdk代理 else { return new JdkDynamicAopProxy(config); } } // 判断是否提供代理类需要实现的接口 private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) { Class<?>[] ifcs = config.getProxiedInterfaces(); return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]))); } }
getProxy方法分析
从对createAopProxy方法的分析可以看到,我们要么执行的是ObjenesisCglibAopProxy中的getProxy方法,要么就是JdkDynamicAopProxy的getProxy方法,二者的区别在于一个是通过cglib的方式生成代理对象,而后者则是通过jdk的方式生成动态代理。
这里我只分析一个JdkDynamicAopProxy,首先我们来看看这个类的继承关系
希望你之前已经阅读过
原创 动态代理学习(一)自己动手模拟JDK动态代理
原创 动态代理学习(二)JDK动态代理源码分析
可以看到这个类本身就是一个InvocationHandler,这意味着当调用代理对象中的方法时,最终会调用到JdkDynamicAopProxy的invoke方法。
所以对于这个类我们起码应该关注两个方法
1.getProxy方法
2.invoke方法
getProxy方法源码如下:
public 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); // 需要明确是否在接口定义了hashCode以及equals方法 // 如果接口中没有定义,那么在调用代理对象的equals方法的时候 // 如果两个对象相等,那么意味着它们的目标对象,通知以及实现的接口都相同 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
我们再来看看到底是怎么获取到需要实现的接口的
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) { // 第一步:获取在配置中指定的需要实现的接口 Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces(); // 第二步:如果没有指定需要实现的接口,但是需要代理的目标类本身就是一个接口 // 那么将其添加到代理类需要实现的接口的集合中 // 如果目标类本身不是一个接口,但是是经过jdk代理后的一个类 // 那么获取这个代理后的类所有实现的接口,并添加到需要实现的接口集合中 if (specifiedInterfaces.length == 0) { Class<?> targetClass = advised.getTargetClass(); if (targetClass != null) { if (targetClass.isInterface()) { advised.setInterfaces(targetClass); } else if (Proxy.isProxyClass(targetClass)) { advised.setInterfaces(targetClass.getInterfaces()); } specifiedInterfaces = advised.getProxiedInterfaces(); } } // 第三步:为代理类添加三个默认需要实现的接口,分别是 // 1.SpringProxy,一个标记接口,代表这个类是通过Spring的AOP代理生成的 // 2.Advised,提供了管理通知的方法 // 3.DecoratingProxy,用户获取到真实的目标对象 // 这个真实对象指的是在嵌套代理的情况下会获取到最终的目标对象 // 而不是指返回这个ProxyFactory的target boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class); boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class); boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class)); int nonUserIfcCount = 0; if (addSpringProxy) { nonUserIfcCount++; } if (addAdvised) { nonUserIfcCount++; } if (addDecoratingProxy) { nonUserIfcCount++; } Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount]; System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length); int index = specifiedInterfaces.length; if (addSpringProxy) { proxiedInterfaces[index] = SpringProxy.class; index++; } if (addAdvised) { proxiedInterfaces[index] = Advised.class; index++; } if (addDecoratingProxy) { proxiedInterfaces[index] = DecoratingProxy.class; } return proxiedInterfaces; }
invoke方法分析
在确认了需要实现的接口后,直接调用了jdk的动态代理方法,这个我们就不做分析了,接下来我们来看看Spring是如何将通知应用到代理对象上的,对应的要分析的代码就是JdkDynamicAopProxy的invoke方法,源码如下:
// 这个方法的代码稍微有点长,代码也比较难,希望大家能耐心看完 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Object target = null; try { // 首先处理的是hashCode跟equals方法 // 如果接口中没有定义这两个方法,那么会调用本类中定义的equals方法 // 前面我们也说过了,只有当两个类的目标对象,通知以及实现的接口都相等的情况下 // equals才会返回true // 如果接口中定义了这两个方法,那么最终会调用目标对象中的方法 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { return equals(args[0]); } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { return hashCode(); } // 也就是说我们调用的是DecoratingProxy这个接口中的方法 // 这个接口中只定义了一个getDecoratedClass方法,用于获取到 // 最终的目标对象,在方法实现中会通过一个while循环来不断接近 // 最终的目标对象,直到得到的目标对象不是一个被代理的对象才会返回 else if (method.getDeclaringClass() == DecoratingProxy.class) { return AopProxyUtils.ultimateTargetClass(this.advised); } // 说明调用的是Advised接口中的方法,这里只是单纯的进行反射调用 else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; // 说明需要将代理类暴露到线程上下文中 // 调用AopContext.setCurrentProxy方法将其放入到一个threadLocal中 if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // 接下来就是真正的执行代理逻辑了 target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); // 先获取整个拦截器链 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // 如果没有进行拦截,直接反射调用方法 if (chain.isEmpty()) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } // 否则开始执行整个链条 else { MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); retVal = invocation.proceed(); } // 这里是处理一种特殊情况,就是当执行的方法返回值为this的情况 // 这种情况下,需要返回当前的代理对象而不是目标对象 Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { 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()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } }
在上面整个流程中,我们抓住核心的两步
1.获取整个拦截器链
2.开始在拦截器链上执行方法
我们先看第一步,对应源码如下:
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) { MethodCacheKey cacheKey = new MethodCacheKey(method); List<Object> cached = this.methodCache.get(cacheKey); if (cached == null) { // 调用了advisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法 cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; }
public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, @Nullable Class<?> targetClass) { List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); // 是否有引入通知 boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); // 获取到所有的通知 for (Advisor advisor : config.getAdvisors()) { // 除了引入通知外,可以认为所有的通知都是一个PointcutAdvisor if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; // config.isPreFiltered:代表的是配置已经过滤好了,是可以直接应用的 // 这句代码的含义就是配置是预过滤的或者在类级别上是匹配的 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { // 接下来要判断在方法级别上是否匹配 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) { // 将通知转换成对应的拦截器 // 有些通知本身就是拦截器,例如环绕通知 // 有些通知需要通过一个AdvisorAdapter来适配成对应的拦截器 // 例如前置通知,后置通知,异常通知等 // 其中MethodBeforeAdvice会被适配成MethodBeforeAdviceInterceptor // AfterReturningAdvice会被适配成AfterReturningAdviceInterceptor // ThrowAdvice会被适配成ThrowsAdviceInterceptor MethodInterceptor[] interceptors = registry.getInterceptors(advisor); // 如果是动态的拦截,会创建一个InterceptorAndDynamicMethodMatcher // 动态的拦截意味着需要根据具体的参数来决定是否进行拦截 if (mm.isRuntime()) { 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; }
在构建好拦截器链后,接下来就是真正执行方法了,对应代码就是
// 先创建一个MethodInvocation MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // 开始在拦截器链上执行这个方法 retVal = invocation.proceed();
最后的关键代码就落在了ReflectiveMethodInvocation的proceed方法
public Object proceed() throws Throwable { // 满足这个条件,说明执行到了最后一个拦截器,那么直接反射调用目标方法 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // 获取到下一个要执行的拦截器 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // 前面构建拦截器链的时候我们可以看到,动态的拦截的话会创建一个InterceptorAndDynamicMethodMatcher InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // 如果匹配失败了,执行拦截器链中的下一个拦截逻辑 return proceed(); } } else { // 调用拦截器中的invoke方法,可以看到这里将this作为参数传入了 // 所以我们在拦截器中调用 MethodInvocation的proceed时又会进行入当前这个方法 // 然后去执行链条中的下一个拦截器 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
总结
本文主要是为下篇文章做准备,下篇文章将会结束整个IOC流程的分析,IOC的最后一步便是为Bean创建代理。本文已经分析了代理的具体创建逻辑,在下篇文章中我们主要结合Spring的启动流程来看一看Spring是如何将通知添加到创建代理的配置信息中去的。
关于整个IOC跟AOP的模块还会有两篇文章,一篇用于结束整个IOC流程,另外一篇专门探讨Spring中循环依赖的解决。完成这两篇文章中,接下来打算用5到7篇文章对Spring的事务管理进行分析!