引言
还是一星期一更的经典栏目,如约而至
上回我们说到了 AOP 的 xml 解析过程,今天这篇文章,我们来讲解“代理子类生成”
入口
代理子类的生成的核心类 AspectJAwareAdvisorAutoProxyCreator,这个类是在解析“proxy-target-class”这个属性的时候进行注册,也就是 ConfigBeanDefinitionParser 的 configureAutoProxyCreator 方法中注册:
public static void registerAspectJAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) { //也就是在这里进行的AspectJAwareAdvisorAutoProxyCreator类的注册工作 BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement)); useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); registerComponentIfNecessary(beanDefinition, parserContext); }
复制代码
现在已经知道代理子类的核心的注入到 spring 中的过程,那么这个类的真正工作过程在哪呢?
看 AspectJAwareAdvisorAutoProxyCreator 的类图,我们可以知道,这个类实现了 SmartInstantiationAwareBeanPostProcessor,所以很容易想到入口应该位于此接口及其父接口(BeanPostProcessor)的相关方法中。实际上确实是这样的。
postProcessBeforeInstantiation(前置处理回调)
调用时机
不知道各位还是否记得之前在 spring 的 IOC 系列中 Bean 创建的过程中的调用时机,如果不记得自己回去再看一下(默认大家都记得😄)
AbstractAutowireCapableBeanFactory#createBean:
//// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) { return bean;}Object beanInstance = doCreateBean(beanName, mbdToUse, args);
复制代码
可以看出,调用发生在 Bean 实例的创建之前。
工作源码
AbstractAutoProxyCreator#postProcessBeforeInstantiation
@Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { Object cacheKey = getCacheKey(beanClass, beanName);
if (beanName == null || !this.targetSourcedBeans.contains(beanName)) { if (this.advisedBeans.containsKey(cacheKey)) { return null; } if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } }
// Create proxy here if we have a custom TargetSource. // Suppresses unnecessary default instantiation of the target bean: // The TargetSource will handle target instances in a custom fashion. if (beanName != null) { TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { this.targetSourcedBeans.add(beanName); Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } }
return null; }
复制代码
这个方法逻辑有点复杂,我们还是分部分去讲解:
是否代理
Spring 首先会对当前的 beanClass 进行检查(是否应该/可以对其进行代理)。
不应该代理的类分为两种情况:
对应代码:
if (beanName == null || !this.targetSourcedBeans.contains(beanName)) { if (this.advisedBeans.containsKey(cacheKey)) { return null; } if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } }
复制代码
其中 AbstractAutoProxyCreator.isInfrastructureClass()方法返回给定的 bean 类是否代表一个不应该被代理的基础设施类。默认实现将 Advices、Advisors 和 AopInfrastructureBeans 视为基础设施类。
protected boolean isInfrastructureClass(Class<?> beanClass) { boolean retVal = Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass) || AopInfrastructureBean.class.isAssignableFrom(beanClass); if (retVal && logger.isTraceEnabled()) { logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]"); } return retVal; }
复制代码
AbstractAutoProxyCreator#shouldSkip()如果给定的 bean 不应被此后处理器考虑自动代理,则子类应覆盖此方法以返回 true 。有时我们需要能够避免这种情况发生,如果它会导致循环引用。此实现返回 false
protected boolean shouldSkip(Class<?> beanClass, String beanName) { return false; }
复制代码
那么此方法跳过的是谁呢?其实就是我们通过 aop:aspect 标签配置的切面,即:
<bean id="aopAdvice" class="base.aop.AopDemoAdvice" /><aop:config> <aop:aspect ref="aopAdvice"> </aop:aspect></aop:config>
复制代码
里的 aopAdvice。
这体现在 AspectJAwareAdvisorAutoProxyCreator 重写其父类的 shouldSkip 方法中
@Override protected boolean shouldSkip(Class<?> beanClass, String beanName) { // TODO: Consider optimization by caching the list of the aspect names List<Advisor> candidateAdvisors = findCandidateAdvisors(); for (Advisor advisor : candidateAdvisors) { if (advisor instanceof AspectJPointcutAdvisor) { if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) { return true; } } } return super.shouldSkip(beanClass, beanName); }
复制代码
从前面的 aop:aspect 标签的解析过程,Spring 对于 aop:config 的解析其实是把 aop:before/after 等标签解析成为了 AspectJPointcutAdvisor 类型的 BeanDefinition,而 aopAdvice 以 AbstractAspectJAdvice 的类型保存在其中。
我们不难得出: Spring 跳过的是适用于当前 bean 的 Advisor 的 Advice/Aspect 对象
到这里,我们可以将 AOP 的逻辑归纳一下,如下图所示:
Advisor 寻找
关键便是 findCandidateAdvisors 方法,最终调用 BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans:
public List<Advisor> findAdvisorBeans() { // Determine list of advisor bean names, if not cached already. String[] advisorNames = null; synchronized (this) { //结果缓存 advisorNames = this.cachedAdvisorBeanNames; if (advisorNames == null) { //去容器中寻找,不要在这里初始化 FactoryBeans:我们需要让所有常规 bean 保持未初始化状态,以便让自动代理创建者应用到它们 advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } } if (advisorNames.length == 0) { return new LinkedList<Advisor>(); }
List<Advisor> advisors = new LinkedList<Advisor>(); for (String name : advisorNames) { if (isEligibleBean(name)) { if (this.beanFactory.isCurrentlyInCreation(name)) { if (logger.isDebugEnabled()) { logger.debug("Skipping currently created advisor '" + name + "'"); } } else { try { advisors.add(this.beanFactory.getBean(name, Advisor.class)); } catch (BeanCreationException ex) { Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) { if (logger.isDebugEnabled()) { logger.debug("Skipping advisor '" + name + "' with dependency on currently created bean: " + ex.getMessage()); } // Ignore: indicates a reference back to the bean we're trying to advise. // We want to find advisors other than the currently created bean itself. continue; } } throw ex; } } } } return advisors; }
复制代码
可以看出,首先是从容器中获取到所有的 Advisor 示例,然后调用 isEligibleBean 方法逐一判断 Advisor 是否适用于当前 bean
适用性检测
确定具有给定名称的方面 bean 是否符合条件。默认实现总是返回 true 。
protected boolean isEligibleAdvisorBean(String beanName) { return true;}
复制代码
而 AbstractAdvisorAutoProxyCreator 的子类 AspectJAwareAdvisorAutoProxyCreator 并没有覆盖此方法,所以此处会对容器中所有的 Advisor 的 Advice 进行跳过。
检测结果缓存因为 postProcessBeforeInstantiation 方法会在每个 bean 初始化之前被调用,所以没有必要每次都真的进行基础类检测和跳过类检测,Spring 使用了 advisedBeans 作为缓存用以提高性能,advisedBeans 是通过 ConcurrentHashMap 实现的一个容器,初始容量为 256。
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<Object, Boolean>(256);
复制代码
TargetSource 从源码中可以看出,对于自定义的 TargetSource,Spring 会立即执行代理子类的创建。Spring 的代理其实是针对 TargetSource 的
//如果我们有自定义 TargetSource,请在此处创建代理。//抑制目标 bean 的不必要的默认实例化://TargetSource 将以自定义方式处理目标实例if (beanName != null) { //为 bean 实例创建目标源。如果设置,则使用任何 TargetSourceCreators。如果不应使用自定义 TargetSource,则返回null 。 //此实现使用“customTargetSourceCreators”属性。子类可以重写此方法以使用不同的机制 TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { this.targetSourcedBeans.add(beanName); //返回是否要代理给定的 bean、要应用的附加建议(例如 AOP 联盟拦截器)和顾问 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); //为给定的 bean 创建一个 AOP 代理 Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } }
复制代码
到这里,beanpostprocessor 中的前置处理回调就讲解完毕,那么我们来看看后置处理的逻辑是怎么样的:
postProcessAfterInitialization(后置处理回调)
AbstractAutoProxyCreator#postProcessAfterInitialization:
@Override public Object postProcessAfterInitialization(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; }
复制代码
wrapIfNecessary:
如有必要,包装给定的 bean,即如果它有资格被代理
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { //自定义TargetSource,已经进行过代理子类生成 if (beanName != null && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
// 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; }
复制代码
Advisor 寻找即 getAdvicesAndAdvisorsForBean 方法,这里进行的便是去容器中寻找适用于当前 bean 的 Advisor,最终调用的是
AbstractAdvisorAutoProxyCreator.findEligibleAdvisors:
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { //findCandidateAdvisors这个方法之前已经说过了,查找出所有的增强 List<Advisor> candidateAdvisors = findCandidateAdvisors(); //搜索给定的候选顾问以查找可以应用于指定 bean 的所有顾问 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); //给定迄今为止获得的排序顾问,子类可以覆盖以注册其他顾问的扩展挂钩。默认实现为空。通常用于添加顾问,这些顾问公开一些后来的顾问所需的上下文信息 extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { //对所有的增强进行排序 eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
复制代码
适用性判断 findAdvisorsThatCanApply 最终调用 AopUtils.findAdvisorsThatCanApply:
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new LinkedList<Advisor>(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { // already processed continue; } if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; }
复制代码
canApply:IntroductionAdvisor 在 Advisor 链中总是位于非 IntroductionAdvisor 前面
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { if (advisor instanceof IntroductionAdvisor) { return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); } else if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { // It doesn't have a pointcut so we assume it applies. return true; } }
复制代码
很明显,对于引入 Advisor 与其它 Advisor 是两种不同的判断方式。引入引入的概念在下面 aop:scoped-proxy 中有提到。因为引入的目的在于动态地向一个类添加另一种功能(接口),所以只要判断给定的类是否是要引入到的类即可其它 AopUtils.canApply:
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null"); //是否Pointcut可以匹配当前类 if (!pc.getClassFilter().matches(targetClass)) { return false; } //是否Pointcut可以匹配所有方法 MethodMatcher methodMatcher = pc.getMethodMatcher(); if (methodMatcher == MethodMatcher.TRUE) { // No need to iterate the methods if we're matching any method anyway... return true; }
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; }
Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); classes.add(targetClass); for (Class<?> clazz : classes) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); for (Method method : methods) { if ((introductionAwareMethodMatcher != null && introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) || methodMatcher.matches(method, targetClass)) { return true; } } }
return false; }
复制代码
Advisor 扩展 AbstractAdvisorAutoProxyCreator.extendAdvisors 允许子类向 Advisor 链表中添加自己的 Advisor。最终调用 AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary 方法。
方法中的逻辑:如果 Advisor 链表中的 Advisor 含有 AspectJ Advice,那么将会把一个 ExposeInvocationInterceptor 添加到链表的表头,目的在于将 MethodInvocation 以 ThreadLocal 的方式暴露给后面所有的 Advisor
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) { // Don't add advisors to an empty list; may indicate that proxying is just not required if (!advisors.isEmpty()) { boolean foundAspectJAdvice = false; for (Advisor advisor : advisors) { // Be careful not to get the Advice without a guard, as // this might eagerly instantiate a non-singleton AspectJ aspect if (isAspectJAdvice(advisor)) { foundAspectJAdvice = true; } } if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) { advisors.add(0, ExposeInvocationInterceptor.ADVISOR); return true; } } return false; }
复制代码
排序即 sortAdvisors 方法,用于对实现了 Ordered 接口的 Advisor 进行排序。
protected List<Advisor> sortAdvisors(List<Advisor> advisors) { AnnotationAwareOrderComparator.sort(advisors); return advisors; }
复制代码
创建这里省去了一些非关键的内容,这里的入口是在 wrapIfNecessary 方法中。AbstractAutoProxyCreator#createProxy
protected Object createProxy( Class<?> beanClass, String beanName, 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); } } //将interceptor适配为Advisor 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()); }
复制代码
spring 通过两种方式去创建代理类,一种是 jdk 动态代理(需要实现接口),一种是 cglib 动态代理(生成一个代理子类),如何决定用那种方式去创建动态代理,则是由 DefaultAopProxyFactory.createAopProxy 方法决定。
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); }}
复制代码
逻辑很明显,如果指定了(proxy-target-classs 设为 true)使用 Cglib,那么就会使用 Cglib 的方式,如果没有指定(或为 false),那么先回检测被代理类是否实现了自己的接口,如果实现了,那么就采用 JDK 动态代理的方式。
jdk 动态代理实现:JdkDynamicAopProxy#getProxy:
@Overridepublic Object getProxy(ClassLoader classLoader) { //找到可以用来进行代理的接口 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); //用来代理的接口中是否定义了equals或者是hashCode方法? //结果保存在内部equalsDefined和hashCodeDefined两个成员变量中 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);}
复制代码
cglib 动态代理实现
@Override public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource()); }
try { Class<?> rootClass = this.advised.getTargetClass(); Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass; if (ClassUtils.isCglibProxyClass(rootClass)) { proxySuperClass = rootClass.getSuperclass(); Class<?>[] additionalInterfaces = rootClass.getInterfaces(); for (Class<?> additionalInterface : additionalInterfaces) { this.advised.addInterface(additionalInterface); } }
// Validate the class, writing log messages as necessary. validateClassIfNecessary(proxySuperClass, classLoader);
// Configure 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 ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
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);
// Generate the proxy class and create a proxy instance. return createProxyClassAndInstance(enhancer, callbacks); } catch (CodeGenerationException 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 (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); } }
复制代码
这里对两种代理的实现没有去非常详细的说明,如果有感兴趣的小伙伴可以自己去跟一下代码。
好了,终于在清明假期的最后一天把这篇文章赶出来了,整个假期在忙着本地和云服务器的项目集成 elk 日志框架(mac 和 linux 会过程细节有些许不同),期间遇到了很多的坑,下个星期可能会加一篇文章来描述我在集成 elk 日志框架的时候碰到的一些问题和如何集成 elk 的过程描述一下,最后看到 elk 成功跑起来的时候,那一瞬间的感动,真的无法言语。
评论