引言
还是一星期一更的经典栏目,如约而至
上回我们说到了 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:
@Override
public 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 成功跑起来的时候,那一瞬间的感动,真的无法言语。
评论