SpringAop源码分析(基于注解)三:创建代理对象

我们先回到Bean初始化之后,调用BeanPostProcessor后置处理器的地方。

//AbstractAutoProxyCreator.java

//在Bean初始化之后回调
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		//判断缓存中是否有
		if (!this.earlyProxyReferences.contains(cacheKey)) {
			// 没有,为 bean 生成代理对象
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

wrapIfNecessary代码:

//AbstractAutoProxyCreator.java

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

	/*
	 * 如果是基础设施类(Pointcut、Advice、Advisor 等接口的实现类),或是应该跳过的类,
	 * 则不应该生成代理,此时直接返回 bean
	 */
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// Create proxy if we have advice.
<1>	// 返回匹配当前 bean 的所有的通知器  advisor、advice、interceptor
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	if (specificInterceptors != DO_NOT_PROXY) {
		this.advisedBeans.put(cacheKey, Boolean.TRUE);
		// 核心!创建代理对象
<2>		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;
}

上篇文章我们主要分析的是<1>处代码,现在有了合适的通知器,我们要为当前Bean创建代理对象,把通知器(Advisor)所持有的通知(Advice)织入到 bean 的某些方法前后。

看代码:

//AbstractAutoProxyCreator.java

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 proxyFactory = new ProxyFactory();
	proxyFactory.copyFrom(this);

	//proxyTargetClass是 @EnableAspectJAutoProxy 的属性之一
	//true -> 强制使用CGLIB代理
	if (!proxyFactory.isProxyTargetClass()) {
		//false
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		}
		else {
			//检测 beanClass 是否实现了接口,若未实现,则将
			//proxyFactory 的成员变量 proxyTargetClass 设为 true
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}
    
        //封装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
  • 判断使用JDK还是CGLIB
  • 封装ProxyFactory
  • 创建并获取代理对象

这里的 isProxyTargetClass() 其实就是我们前面用的注解@EnableAspectJAutoProxy的属性之一,当其为true时,强制使用CGLIB代理。

下面我们接着看创建代理的代码:

//ProxyFactory.java

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

这段方法有两个方法调用:

  • createAopProxy() 创建 AopProxy 实现类对象
  • getProxy(classLoader) 创建代理对象

我们先来看下createAopProxy():

//DefaultAopProxyFactory.java

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	//if中的3个条件
	//1、 config.isOptimize() - 是否需要优化
	//2、 config.isProxyTargetClass() - 检测 proxyTargetClass 的值
	//3、 hasNoUserSuppliedProxyInterfaces(config) - 目标 bean 是否实现了接口
	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.");
		}
		//如果目标类是一个接口 || 或者目标类是一个代理类
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			//创建JdkDynamicAopProxy
			return new JdkDynamicAopProxy(config);
		}
		//创建CglibAopProxy
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		//创建JdkDynamicAopProxy
		return new JdkDynamicAopProxy(config);
	}
	}

最终调用的是DefaultAopProxyFactory#createAopProxy(...)方法,通过这个方法创建AopProxy 的实现类,如: JdkDynamicAopProxy,然后根据这个实现类再创建代理对象。

我们以JdkDynamicAopProxy为例,看下getProxy(classLoader):

//JdkDynamicAopProxy.java

public Object getProxy() {
    return getProxy(ClassUtils.getDefaultClassLoader());
}

public Object getProxy(ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
    }
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    
    // 调用 newProxyInstance 创建代理对象
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

直接看代码最后一行,最终调用 Proxy.newProxyInstance 方法创建代理对象。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏赵KK日常技术记录

JAVA线程杂谈记录

本来前天就更的,后来删掉了,思前想后觉得不合适,毕竟是别人的辛苦原创,在得到本人允许的情况,根据视频,整理资料,虽然是私人公众号,但有可能因此获...

6310
来自专栏EffectiveCoding

Spring AOP

Spring AOP 使用场景蛮多的属性检查、日志等,所有拦截下来可以在切面共同做的事儿似乎都可以用AOP(面向切面)的方式解决。在面试的过程中AOP 也是除I...

8610
来自专栏自学测试之道

RF+Allure+Jenkins 自动化持续集成环境搭建

前期篇章主要讲解了Robot Framework的环境搭建,基本配置和一些实例教程。随着行业的发展和项目的快速迭代过程,持续交付、持续集成和持续测试迫不及待。上...

9240
来自专栏IT大咖说

你以为反射真的不能为所欲为?至少JDK8以后很强

这里就不在赘述如何通过Method对象调用方法了。文章末尾会给出上一章节的地址。今天我们要研究的是Method如何获取方法参数这一块。看似简单却又是那么的传奇。...

8220
来自专栏实时计算

Hbase入门(二)——安装与配置

本文讲述如何安装,部署,启停HBase集群,如何通过命令行对Hbase进行基本操作。

11320
来自专栏java大数据

用java自带jdk开发第一个java程序

下面要讲的eclipse要想正常工作,需要先学会配置这里的jdk。jdk要想正常工作,需先学会配置JAVA_HOME和ClassPath和Path,可参见网站配...

1200
来自专栏微信公众号【Java技术江湖】

夯实Java基础系列12:深入理解Java中的反射机制

本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看

8900
来自专栏Java程序员那些事

JDK7的Comparison method violates its general contract异常

前一阵遇到了一个使用Collections.sort()时报异常的问题,跟小伙伴@zhuidawugui 一起排查了一下,发现问题的原因是JDK7的排序实现改为...

7010
来自专栏芋道源码1024

IntelliJ IDEA 2019.3 这回真的要飞起来了,新特性抢先看!

IntelliJ IDEA 上周才公布下一个主要版本 2019.3 的 Roadmap,近日就发布了 IntelliJ IDEA 2019.3 的首个早期访问版...

15720
来自专栏自学测试之道

记录查看系统应用APK签名方式

【】因为每个公司的业务不同,所以会在某些自研的应用APK上进行签名,下面讲解下如何查看应用APK签名

13820

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励