spring5源码阅读(八)jdk和cglib动态代理选择过程详解

本文分析下spring动态代理的入口以及两种动态代理方式(基于jdk和基于cglib)的选择。

先准备个小demo,假设我们写了个aop切面(不熟悉aop的参考文章《@Aspect 一个简单的注解式 spring Aop demo》
切点就是所有service方法,假设我们只有一个service,如下:
在这里插入图片描述
同时配置类上要加注解@EnableAspectJAutoProxy,表示开启动态动态代理功能:
在这里插入图片描述
先提前特别说明下,

  • 此注解spring默认表示使用基于jdk的动态代理方式,如果设置里面的参数proxyTargetClass参数为true,才表示使用cglib动态代方式。
  • jdk动态代理,是基于接口实现;cglib不用接口,直接继承被代理类实现代理类。

1. AnnotationAwareAspectJAutoProxyCreator

在之前的文章《spring5源码阅读(六)Spring Bean的生命周期详解》中,我们大致分析过,在AbstractAutowireCapableBeanFactory#doCreateBean中完成了bean的创建,即实例化+初始化;
其中的如下一行代码,就是在进行初始化过程:
exposedObject = initializeBean(beanName, exposedObject, mbd);

打开initializeBean方法,最后有如下一行:
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

此方法就是执行所有后置处理器的回调方法。

打断点就会发现其中有个叫AnnotationAwareAspectJAutoProxyCreator 的post process,类图如下:
在这里插入图片描述
在其父类 AbstractAutoProxyCreator 中,执行了回调方法,

@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
		if (bean != null) {
		   //被代理的类名(比如CommonServiceImpl)
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			//判断被代理的目标类不是预初始化状态,earlyProxyReferences是为了解决循环依赖的
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				//这里发生代理
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

上面核心方法就是wrapIfNecessary(bean, beanName, cacheKey);
打开:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		//如果已经被实现了代理,则直接返回
		if (StringUtils.hasLength(beanName) && 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;
	}

核心方法createProxy().

2. jdk动态代理和cglib动态代理如何选择?

上面我们已经找到了创建代理的方法createProxy,继续跟进:

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

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}
		//ProxyFactory创建代理类的工厂,因为有jdk和cglib两种
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		//proxyFactory.isProxyTargetClass()默认是false
		if (!proxyFactory.isProxyTargetClass()) {
			//根据最开始@EnableAspectJAutoProxy注解中的proxyTargetClass参数判断是否应该使用cglib代理
			if (shouldProxyTargetClass(beanClass, beanName)) {
			//标识 使用cglib动态代理
				proxyFactory.setProxyTargetClass(true);
			} else {
			    //评估接口的合理性,一些内部回调接口,比如InitializingBean等,不会被实现jdk代理
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		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());
	}

几点说明:

  • 代理类由代理工厂ProxyFactory实现;
  • proxyFactory.isProxyTargetClass()默认为false,表示没有开启cglib代理方式;
  • shouldProxyTargetClass(beanClass, beanName)方法用来判断@EnableAspectJAutoProxy注解中的proxyTargetClass参数
protected boolean shouldProxyTargetClass(Class<?> beanClass, @Nullable String beanName) {
	return (this.beanFactory instanceof ConfigurableListableBeanFactory &&
			AutoProxyUtils.shouldProxyTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName));
}
继续进入:
public static boolean shouldProxyTargetClass(ConfigurableListableBeanFactory beanFactory, @Nullable String beanName) {
	if (beanName != null && beanFactory.containsBeanDefinition(beanName)) {
		BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
		//判断目标类中的proxyTargetClass(PRESERVE_TARGET_CLASS_ATTRIBUTE)参数是否为true
		return Boolean.TRUE.equals(bd.getAttribute(PRESERVE_TARGET_CLASS_ATTRIBUTE));
	}
	return false;
}
  • evaluateProxyInterfaces是用来校验接口的合理性,比如InitializingBean这样的内部回调接口,不会被实现jdk动态代理。

继续代码深入:

public Object getProxy(@Nullable ClassLoader classLoader) {
	return createAopProxy().getProxy(classLoader);
}

上面getProxy(classLoader);方法是得到代理类,这个不重要,关键是前边使用哪种方式得到代理类,
所以 createAopProxy() 方法很关键,打开如下:

protected final synchronized AopProxy createAopProxy() {
	if (!this.active) {
		activate();
	}
	//createAopProxy():根据@EnableAspectJAutoProxy中的proxyTargetClass属性判断返回jdk代理还是Cglib代理
	//默认为jdk代理
	return getAopProxyFactory().createAopProxy(this);
}

上面最后的核心来了!!,打开createAopProxy(this)方法,如下:

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	//config.isProxyTargetClass():是否开启了cglib动态代理
	//hasNoUserSuppliedProxyInterfaces:被代理的类没有实现接口
	if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
		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.");
		}
		//目标类是否是接口,是接口的化就用jdk动态代理
		//否则,即使没开启cglib动态代理,也只能用cglib
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

这段代码就是spring选择jdk还是cglab的实现逻辑了,
几点说明:

  • 如果配置类的@EnableAspectJAutoProxy注解没有配置proxyTargetClass参数为true,默认使用jdk动态代理实现;
  • 但是,如果一个被代理的目标类,比如本文开始的CommonServiceImpl,它如果没有实现CommonService接口,那么spring也只能选择cglib动态代理方式;
  • 同样,如配置指定默认使用了cglib,但是被代理类是个接口,那么也不能使用cglib,只能使用jdk动态代理。

3. jdk动态代理于cglib动态代理区别

上边分析下来,我们知道,spring默认基于jdk的动态代理实现,即便如此。有些情况下,也只能使用cglib动态代理实现。

  • jdk动态代理基于接口实现,被代理对象必须实现某接口,代理对象同样会实现此接口,在复制了被代理对象的方法后,在进行一定增强处理;
  • cglib代理实现不需要接口,或者被代理类由于历史原因就没有实现接口,那么此时spring会采用cglib,代理对象直接继承被代理对象,然后进行增强;
发布了62 篇原创文章 · 获赞 29 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/csdn_20150804/article/details/102734317