在Spring AOP使用(踩坑)实践总结​及IOC容器的依赖注入详解我们提到过,当Bean实例化过程中会触发BeanPostProcessor的动作。其中AbstractAutoProxyCreator的postProcessAfterInitialization方法中我们可以看到其会尝试对Bean进行代理。

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 获取缓存key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 如果earlyProxyReferences中不存在 {cacheKey,bean},执行wrapIfNecessary
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

本文我们尝试分析Spring AOP如何对bean进行包装代理的。假设我们定义了切片如下所示:

@Aspect
@Component
public class LogAspect {

@Pointcut("execution(* com.recommend.controller.*.*(..))")
public void logPointCut() {
}

@Before(value = "execution(* com.recommend.controller.*.*(..))")
public void beforeMethod(JoinPoint point) {
System.out.println(" before(Joinpoint point)");
}

@After("logPointCut()")
public void afterMethod(JoinPoint point) {
System.out.println(" afterMethod(Joinpoint point)");
}

@AfterReturning(pointcut = "logPointCut()",returning="result")
public void AfterReturning(JoinPoint point,Object result) {
System.out.println(" AfterReturning(Joinpoint point)");
}
@AfterThrowing(value = "logPointCut()",throwing="exception")
public void AfterThrowing(JoinPoint point,Exception exception) {
System.out.println(" AfterThrowing(Joinpoint point)");
}

@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
// 执行方法
Object result = point.proceed();
// 执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
//异步保存日志
return result;
}
}

接下来我们来看​​AbstractAutoProxyCreator​​​的​​wrapIfNecessary​​方法。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 如果当前bean有自定义targetSource,直接返回
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}

// 如果当前bean无需代理,直接返回
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}

//如果当前bean是Advice、Pointcut、Advisor或者AopInfrastructureBean可以直接返回
//如果当前bean是original instance,那么也直接返回,如XXXX.ORIGINAL 命名的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);
// DO_NOT_PROXY=null
if (specificInterceptors != DO_NOT_PROXY) {

// 保存代理标志 Map<Object, Boolean> advisedBeans
this.advisedBeans.put(cacheKey, Boolean.TRUE);

// 创建代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

// Map<Object, Class<?>> proxyTypes 保存代理类型
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// 走到这里说明无需创建代理
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

从上面方法我们可以看到,如果当前bean拥有advice,也就是我们定义的切面表达式拦截了当前bean的某个方法,那么就会尝试创建代理并在advisedBeans存储代理标志。

这里有这样关键的两步:

  • getAdvicesAndAdvisorsForBean获取advice
  • createProxy,创建代理

【1】getAdvicesAndAdvisorsForBean

我们先看一下获取到的​​Object[] specificInterceptors​​是个什么。如下所示,在这里其获取到是一个advisor数组,每个advisor呢主要有pointcut与advice组成。前者表示连接点,后置表示应用的增强通知。

那么为什么用specificInterceptors命名呢,而且其方法名字是getAdvicesAndAdvisorsForBean。也就是说这里不仅仅是advisor,还可能是advice。

Spring AOP中如何为Bean创建代理?_Spring

如下所示,在AbstractAutoProxyCreator内部其是一个抽象方法并没有提供实现。

@Nullable
protected abstract Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,
@Nullable TargetSource customTargetSource) throws BeansException;

主要的实现在子类AbstractAdvisorAutoProxyCreator中。

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}

这里我们继续看​​findEligibleAdvisors(beanClass, beanName)​​方法。

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 使用advisorRetrievalHelper找到容器中所有的Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();

// 为当前bean从候选candidateAdvisors找到可以应用的advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

// 扩展Advisor 如果eligibleAdvisors不为空则在首位添加ExposeInvocationInterceptor.ADVISOR
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 使用AnnotationAwareOrderComparator进行排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}

第一步,​​findCandidateAdvisors​​​方法使用​​advisorRetrievalHelper​​​找到容器中的Advisor,然后调用​​AbstractAdvisorAutoProxyCreator.BeanFactoryAdvisorRetrievalHelperAdapter#isEligibleBean​​方法判断是否是合适的/有资格的()。最后将所有适合的advisor从容器中得到返回(如果advisor没有实例化将会触发实例化过程)。

如下图所示,我们自定义的logAspect也在列。
Spring AOP中如何为Bean创建代理?_动态代理_02

判断当前advisor是否是合适的方法如下所示。

// InfrastructureAdvisorAutoProxyCreator#isEligibleAdvisorBean
@Override
protected boolean isEligibleAdvisorBean(String beanName) {
return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}

第二步,findAdvisorsThatCanApply方法从上面得到的候选Advisor中寻找到可以应用到目标Bean的advisor。

// AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}

如果当前advisor是IntroductionAdvisor,那么将会得到其ClassFilter然后调用matches方法默认​​DefaultIntroductionAdvisor​​的matches方法是true。

如果是PointcutAdvisor,那么将会获取到Pointcut进而得到MethodMatcher。最终会通过MethodMatcher与目标类的所有方法进行匹配

第三步,extendAdvisors扩展advisor。这是给子类提供的一个扩展钩子,允许子类覆盖该方法并注册额外Advisor。默认实现是空,子类AspectJAwareAdvisorAutoProxyCreator重写了该方法。

//AspectJAwareAdvisorAutoProxyCreator#extendAdvisors
@Override
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
// 如果advisor包含advice且candidateAdvisors没有ExposeInvocationInterceptor.ADVISOR,
// 则尝试将其加入candidateAdvisors

Spring AOP中如何为Bean创建代理?_动态代理_03

第四步,如果最终eligibleAdvisors 不为空,那么将使用AnnotationAwareOrderComparator进行排序(按照advisor的order值进行排序)。

排序后的结果是(从上到下):

AfterThrowing>AfterReturning>After>Around>Before

Spring AOP中如何为Bean创建代理?_ide_04

至此,我们得到了​​List<Advisor> advisors​​,转换为array返回。

【2】创建代理

也就是下面这句代码。

// AbstractAutoProxyCreator#createProxy
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors,
new SingletonTargetSource(bean));

那么接下来我们分析createProxy这个方法。

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {

// 记录原始bean 类型,放到关联的beanDefinition的Map<String, Object> attributes中
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}

// 创建代理工厂,用来获取AopProxy
ProxyFactory proxyFactory = new ProxyFactory();
// 设置属性 如proxyTargetClass
proxyFactory.copyFrom(this);

// 判断proxyTargetClass,默认为false,
//在实例化时ProxyConfig的proxyTargetClass会被设置为true
// true则意味着目标targetClass非接口时使用CGLIB对bean进行代理
if (!proxyFactory.isProxyTargetClass()) {
//是否代理目标类,这时采用cglib进行代理
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 这时采用JDK动态代理
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}

// 从specificInterceptors获取Advisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);

//设置proxyFactory
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);

//提供子类进行重写的,默认为空
customizeProxyFactory(proxyFactory);

// 设置冻结属性,freezeProxy默认为false
proxyFactory.setFrozen(this.freezeProxy);

// 默认为false AbstractAdvisorAutoProxyCreator覆盖该方法返回true
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//根据代理工厂获取具体代理如ObjenesisCglibAopProxy
//然后为bean创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}

根据代码来看,首先是为当前beanDefinition记录了bean的原始类型。然后实例化ProxyFactory 对其进行设置如advisors、targetSource、Frozen及PreFiltered。之后使用代理工厂获取具体AopProxy如​​ObjenesisCglibAopProxy​​​或者​​JdkDynamicAopProxy​​。根据具体的AopProxy对目标Bean进行代理包装。

Spring AOP中如何为Bean创建代理?_ide_05

那么这里我们着重分析两块:

  • buildAdvisors ,解析得到Advisor数组
  • proxyFactory.getProxy(getProxyClassLoader());,创建代理对象

① buildAdvisors

Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);

protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
// Handle prototypes correctly...
Advisor[] commonInterceptors = resolveInterceptorNames();

// 如果有公共的拦截器且applyCommonInterceptorsFirst为true,
// 则放在allInterceptors第一个位置
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
allInterceptors.addAll(Arrays.asList(specificInterceptors));
if (commonInterceptors.length > 0) {
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
}
else {
// 否则直接addAll,不指定位置
allInterceptors.addAll(Arrays.asList(commonInterceptors));
}
}
}
if (logger.isTraceEnabled()) {
int nrOfCommonInterceptors = commonInterceptors.length;
int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
logger.trace("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
" common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
}

// 对每一个allInterceptors中的对象进行包装得到Advisor
Advisor[] advisors = new Advisor[allInterceptors.size()];
for (int i = 0; i < allInterceptors.size(); i++) {
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}

如上代码所示,先尝试得到公共的拦截器,如果有则放到allInterceptors中。然后对对每一个allInterceptors中的对象进行包装得到Advisor。

这里我们解释一下拦截器。在前面源码我们可以看到诸多xxxxInterceptor命名的变量,这个其实和我们通常理解的Interceptor接口不一样,这里是业务含义指拦截方法处理前后进行增强通知,具体的bean可能是​​InstantiationModelAwarePointcutAdvisorImpl​​​或者​​ExposeInvocationInterceptor.ADVISOR​​。

我们继续往下看DefaultAdvisorAdapterRegistry是如何对adviceObject进行包装返回Advisor的。

public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}

方法解释如下:

  • ① 如果是Advisor,直接返回;
  • ② 如果不是Advice,抛出异常UnknownAdviceTypeException
  • ③ 如果是MethodInterceptor,返回DefaultPointcutAdvisor;
  • ④ 尝试返回DefaultPointcutAdvisor
  • ⑤ 抛出异常DefaultPointcutAdvisor

默认在构建DefaultAdvisorAdapterRegistry实例时注册了三个适配器。

public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}

至此我们解析得到了Advisor,就可以交给ProxyFactory创建代理了。

② proxyFactory.getProxy

如下所示ProxyFactory的getProxy方法。

// ProxyFactory#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}

这里最终会走两个分支:JdkDynamicAopProxy和CglibAopProxy。我们先看一下createAopProxy()

ProxyCreatorSupport的createAopProxy方法。

protected final synchronized AopProxy createAopProxy() {
//如果为激活,进行激活
if (!this.active) {
activate();
}
// 这里默认是DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}

/**
* Activate this proxy configuration.
*/
private void activate() {
this.active = true; // 设置为true
// 遍历监听,默认情况下不存在AdvisedSupportListener
for (AdvisedSupportListener listener : this.listeners) {
listener.activated(this);
}
}

DefaultAopProxyFactory的createAopProxy得到具体的AopProxy

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 如果optimize为true或者proxyTargetClass为true或者 是否有非SpringProxy接口超类
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {

// 这里其实是从targetSource中获取targetClass
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.");
}
// 如果targetClass是接口或者其是一个Proxy代理类
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}

这里会根据targetClass是类 or 接口返回​​ObjenesisCglibAopProxy​​​或者​​JdkDynamicAopProxy​​。

那么接下来就该执行具体的getProxy(classLoader)方法了。

③ JdkDynamicAopProxy创建代理

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 获取代理的接口类型数组
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);

// 判断接口是否有equals 或者 hashCode方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);

// 生成代理
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

④ CglibAopProxy创建代理

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}

try {
// 获取targetClass
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

Class<?> proxySuperClass = rootClass;
// CGLIB_CLASS_SEPARATOR = "$$";
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
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);
//设置接口,如SpringProxy Advised
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
// SpringNamingPolicy
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));

// 这里是核心,设置回调拦截器,如DynamicAdvisedInterceptor
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 | 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);
}
}

在ObjenesisCglibAopProxy中实现了代理实例的创建与回调的设置。

@Override
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
Class<?> proxyClass = enhancer.createClass();
Object proxyInstance = null;

if (objenesis.isWorthTrying()) {
try {
proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
}
catch (Throwable ex) {
logger.debug("Unable to instantiate proxy using Objenesis, " +
"falling back to regular proxy construction", ex);
}
}

if (proxyInstance == null) {
// Regular instantiation via default constructor...
try {
Constructor<?> ctor = (this.constructorArgs != null ?
proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
proxyClass.getDeclaredConstructor());
ReflectionUtils.makeAccessible(ctor);
proxyInstance = (this.constructorArgs != null ?
ctor.newInstance(this.constructorArgs) : ctor.newInstance());
}
catch (Throwable ex) {
throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
"and regular proxy instantiation via default constructor fails as well", ex);
}
}

((Factory) proxyInstance).setCallbacks(callbacks);
return proxyInstance;
}

【3】AOP两种代理

Spring 提供了两种方式来生成代理对象: JDKProxy 和 Cglib,具体使用哪种方式生成由
AopProxyFactory 根据 AdvisedSupport 对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK 动态代理技术,否则使用 Cglib 来生成代理。

① JDK动态接口代理

JDK 动态代理主要涉及到 java.lang.reflect 包中的两个类:Proxy 和 InvocationHandler。

InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。Proxy 利用 InvocationHandler 动态创建一个符合某一接口的实例,生成目标类的代理对象。

JDK动态代理只能为接口创建动态代理实例,而不能对类创建动态代理。需要获得被目标类的 接口信息(应用Java的反射技术),生成一个实现了代理接口的动态代理类(字节码),再通过 反射机制获得动态代理类的构造函数,利用构造函数生成动态代理类的实例对象,在调用具体方法前调用invokeHandler方法来处理。

② CGLib 动态代理

CGLib 全称为 Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展 Java 类与实现 Java 接口,CGLib 封装了 asm,可以在运行期动态生成新的 class。CGLib动态代理需要依赖asm包,把被代理对象类的class文件加载进来,修改其字节码生成 子类

JDK 创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过 CGLib 创建动态代理。

参考博文:
​Java中的代理模式与动(静)态代理Java中动态代理使用与原理详解CGLIB动态代理使用与原理详解