在Spring中通过创建代理可以给bean进行增强,也就是著名的AOP,比如事务就通过在对应的接口或实现类、方法上添加@Transactional进行事务的管理,这个功能主要是在对应的bean实例化的过程中通过后置处理器完成的(具体参考类BeanFactoryTransactionAttributeSourceAdvisor)。主要的代码如下:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
/**
* Initialize the given bean instance, applying factory callbacks
* as well as init methods and bean post processors.
* <p>Called from {@link #createBean} for traditionally defined beans,
* and from {@link #initializeBean} for existing bean instances.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the bean definition that the bean was created with
* (can also be {@code null}, if given an existing bean instance)
* @return the initialized bean instance (potentially wrapped)
* @see BeanNameAware
* @see BeanClassLoaderAware
* @see BeanFactoryAware
* @see #applyBeanPostProcessorsBeforeInitialization
* @see #invokeInitMethods
* @see #applyBeanPostProcessorsAfterInitialization
*/
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.containsKey(cacheKey)) {
// 进行增强
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
/**
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* @param bean the raw bean instance
* @param beanName the name of the bean
* @param cacheKey the cache key for metadata access
* @return a proxy wrapping the bean, or the raw bean instance as-is
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.containsKey(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;
}
在Spring中,就是通过继承AbstractAutoProxyCreator类来实现AOP功能的。在生成代理(createProxy)的时候除了当前的bean的相关信息之外,必不可少的就是specificInterceptors,而这个玩意就是就是增强的逻辑,通过getAdvicesAndAdvisorsForBean这个方法返回的。通过查看Spring中的实现,可以知道这个增强器类型是org.springframework.aop.Advisor。
以下为对应的UML图
比如说现在在Spring容器中添加了一个如下的增强器:
/**
* 性能日志落地数据库 Advisor
*/
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@Component
public class TracePerformanceDatabaseAdvisor extends AbstractPointcutAdvisor {
/**
* 拦截器
*/
private Advice advice;
/**
* 切入点
*/
private Pointcut pointcut;
public TracePerformanceDatabaseAdvisor(){
this.advice = new TraceDatabaseInterceptor();
this.pointcut = new TracePerformancePointcut();
}
@Override
public Pointcut getPointcut() {
return pointcut;
}
@Override
public Advice getAdvice() {
return advice;
}
}
那么现在容器中的bean就会被增强,比如下图
但是如果不想给容器中所有的bean都进行增强,该如何处理呢?
此时就需要增对特定的bean进行增强了,比如说只对com.xquant.platform.test.trade.trace这个包下的bean只进行增强,那么该如何处理呢?这个时候不能将TracePerformanceDatabaseAdvisor注册到容器中,这样在容器中的AutoProxyCreator就不会查找到这个增强器,然后也就不会增强所有的bean。然后再单独创建一个AutoProxyCreator按照自己的逻辑对符合要求的bean进行增强。
- 首先取消注册对应的增强器到容器中(去掉@Component)
- 然后再编写如下AutoProxyCreator
@Component
public class TraceAbstractAutoProxyCreator extends AbstractAutoProxyCreator {
private static final long serialVersionUID = 1L;
private static final String NEED_PROXY_PACKAGE = "com.xquant.platform.test.trade.trace";
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,
TargetSource customTargetSource) throws BeansException {
// 本代理创建器的增强器
return new Object[] { new TracePerformanceDatabaseAdvisor() };
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
boolean needProxy = false;
boolean aopProxy = AopUtils.isAopProxy(bean) || AopUtils.isCglibProxy(bean);
if (aopProxy) {
Class<?> targetClass = AopUtils.getTargetClass(bean);
// 代理类的目标类名是以特定包开头的
needProxy = targetClass.getName().startsWith(NEED_PROXY_PACKAGE);
} else {
needProxy = bean.getClass().getName().startsWith(NEED_PROXY_PACKAGE)
|| beanName.startsWith(NEED_PROXY_PACKAGE);
}
if (needProxy) {
return super.postProcessAfterInitialization(bean, beanName);
} else {
return bean;
}
}
}
那么此时只有在指定的包中的类会进行增强了,如下所示:
此时由于自定义了一个新的AutoProxyCreator,与其他的AutoProxyCreator处于同等的地位,通过遍历对bean进行增强的,增强之后就将增强的对象放在SingletonTargetSource。一层套一层而已。
问题一: 在前置处理中被增强
实际测试的时候,发现其他的bean依旧进行了增强,因为AbstractAutoProxyCreator的实现类中有两个地方可以进行增强,另一个方法为getEarlyBeanReference。这个方法会在将单例放到缓存(解决循环依赖时)中执行:
对应源码如下:
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
/**
* Obtain a reference for early access to the specified bean,
* typically for the purpose of resolving a circular reference.
* @param beanName the name of the bean (for error handling purposes)
* @param mbd the merged bean definition for the bean
* @param bean the raw bean instance
* @return the object to expose as bean reference
*/
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return null;
}
}
}
}
return exposedObject;
}
所以修改TraceAbstractAutoProxyCreator类实现为:
@Component
public class TraceAbstractAutoProxyCreator extends AbstractAutoProxyCreator {
private static final long serialVersionUID = 1L;
private static final String NEED_PROXY_PACKAGE = "com.xquant.platform.test.trade.trace";
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,
TargetSource customTargetSource) throws BeansException {
// 本代理创建器的增强器
return new Object[] { new TracePerformanceDatabaseAdvisor() };
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
boolean needProxy = false;
boolean aopProxy = AopUtils.isAopProxy(bean) || AopUtils.isCglibProxy(bean);
if (aopProxy) {
Class<?> targetClass = AopUtils.getTargetClass(bean);
// 代理类的目标类名是以特定包开头的
needProxy = targetClass.getName().startsWith(NEED_PROXY_PACKAGE);
} else {
needProxy = bean.getClass().getName().startsWith(NEED_PROXY_PACKAGE)
|| beanName.startsWith(NEED_PROXY_PACKAGE);
}
if (needProxy) {
return super.postProcessAfterInitialization(bean, beanName);
} else {
return bean;
}
}
}
问题二:目标bean可能被多次增强,而不是一次增强
通过AopUtils.getTargetClass(bean)返回的是当前被增强前的target对象,而不是最开始被增强的那个原始bean。需要通过递归获取的最开始的类型。
package com.xquant.platform.test.config;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.beans.BeansException;
import org.springframework.stereotype.Component;
import com.xquant.platform.component.prettytrace.advisor.TracePerformanceDatabaseAdvisor;
/**
* 仅仅给用于测试日志的服务类进行增强
* @author guanglai.zhou
* @date 2020年5月14日-下午8:21:03
*/
@Component
public class TraceAbstractAutoProxyCreator extends AbstractAutoProxyCreator {
private static final long serialVersionUID = 1L;
private static final String NEED_PROXY_PACKAGE = "com.xquant.platform.component.trade.trace";
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,
TargetSource customTargetSource) throws BeansException {
// 本代理创建器的增强器
return new Object[] { new TracePerformanceDatabaseAdvisor() };
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
boolean needProxy = false;
boolean aopProxy = AopUtils.isAopProxy(bean);
if (aopProxy) {
Object target = bean;
// 如果Spring的版本为4.3.8或以上 直接调用AopProxyUtils.getSingletonTarget(target)就可以获取target对象了
while (target instanceof Advised) {
TargetSource targetSource = ((Advised) target).getTargetSource();
if (targetSource instanceof SingletonTargetSource) {
target = ((SingletonTargetSource) targetSource).getTarget();
}
}
Class<?> targetClass = AopUtils.getTargetClass(target);
// 代理类的目标类名是以特定包开头的
needProxy = targetClass.getName().startsWith(NEED_PROXY_PACKAGE);
} else {
needProxy = bean.getClass().getName().startsWith(NEED_PROXY_PACKAGE)
|| beanName.startsWith(NEED_PROXY_PACKAGE);
}
if (needProxy) {
return super.postProcessAfterInitialization(bean, beanName);
} else {
return bean;
}
}
}