本文分析下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,代理对象直接继承被代理对象,然后进行增强;