java中针对特定包进行动态代理增强

在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进行增强。

  1. 首先取消注册对应的增强器到容器中(去掉@Component)
  2. 然后再编写如下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;
		}
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lang20150928

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值