返回顶部
首页 > 资讯 > 后端开发 > Python >Spring源码学习之动态代理实现流程
  • 534
分享到

Spring源码学习之动态代理实现流程

2024-04-02 19:04:59 534人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

注:这里不阐述spring和aop的一些基本概念和用法,直接进入正题。 流程   Spring所管理的对象大体会经过确定实例化对象类型、推断构造方法创建对象

注:这里不阐述springaop的一些基本概念和用法,直接进入正题。

流程

  Spring所管理的对象大体会经过确定实例化对象类型、推断构造方法创建对象(实例化)、设置属性、初始化等等步骤。在对象初始化阶段,Spring为开发者提供了一个BeanPostProcessor接口,它会在对象初始化之前和初始化之后被调用(初始化,不是实例化,对应实例化的是InstantiationAwareBeanPostProcessor接口)。


public interface BeanPostProcessor {
	//初始化之前
	Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
	//初始化之后
	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

  在对象初始化之后会调用postProcessAfterInitialization方法,该方法返回一个Object。如果成功返回了一个对象,那么容器中相应beanName对应的实例就将会是这个对象。

  本文主要分析动态代理,我们着重看AnnotationAwareAspectJAutoProxyCreator。先来看一下它的继承关系:

  AnnotationAwareAspectJAutoProxyCreator最终实现了BeanPostProcessor接口(也实现了InstantiationAwareBeanPostProcessor接口),可以看到继承关系比较复杂。当前我们关注的postProcessAfterInitialization方法实现在它的父类AbstractAutoProxyCreator中(只保留了部分代码):


public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				return wrapifNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

  这里主要看看wrapIfNecessary方法(只保留了部分代码):


Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		......
		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;
		}
		......
}

  其中核心的是两个方法调用,分别是getAdvicesAndAdvisorsForBean和createProxy。getAdvicesAndAdvisorsForBean会返回一个对象数组,包含aop相关的一些对象,如果是一个普通的不需要代理的对象会返回一个空Object数组,也就是DO_NOT_PROXY;createProxy方法则是创建代理类。

  先看看getAdvicesAndAdvisorsForBean方法:


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

  getAdvicesAndAdvisorsForBean方法在当前类(AbstractAutoProxyCreator)中是一个抽象方法,由子类AbstractAdvisorAutoProxyCreator实现:


public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
	@Override
	protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}
}

  代码很清晰,我们进入findEligibleAdvisors方法,看方法名也知道它会完成寻找Advisor的工作:


protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		//寻找Advisor
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		//针对指定的bean,过滤可用的Advisor,比如根据注解匹配
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

  首先进入findCandidateAdvisors方法:


protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		return advisors;
	}

  我们这里主要看看aspectj的逻辑,所以看看aspectJAdvisorsBuilder.buildAspectJAdvisors方法(只保留了主要代码):


public List<Advisor> buildAspectJAdvisors() {
		List<String> aspectNames = null;
		......
		synchronized (this) {
			aspectNames = this.aspectBeanNames;
			if (aspectNames == null) {
				//获取所有管理的beanName
				String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
				//遍历每个beanName
				for (String beanName : beanNames) {
					//从beanFactory获取Class
					Class<?> beanType = this.beanFactory.getType(beanName);
					//检查对应的Class是否实现Aspect注解
					if (this.advisorFactory.isAspect(beanType)) {
						//说明这个beanName对应的类是一个切面	
						aspectNames.add(beanName);
						AspectMetadata amd = new AspectMetadata(beanType, beanName);
						if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
							MetadataAwareAspectInstanceFactory factory =
									new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
							//获取Advisor,主要是解析对象中关于AOP的注解,比如Pointcut
							List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
							if (this.beanFactory.isSingleton(beanName)) {
								//就放入缓存,后面就不用重新解析了
								this.advisorsCache.put(beanName, classAdvisors);
							}
							advisors.addAll(classAdvisors);
						}
					}
				}
				this.aspectBeanNames = aspectNames;
				return advisors;
			}
		}
	......
}

  会从beanFactory中寻找所有管理的beanName,返回一个String数组,然后遍历数组,从beanFactory中根据beanName获取对应的Class,然后再看对应的Class是否有Aspect注解,如果有对应的注解,那么就表示这个对象是一个切面。接下来就需要进行解析,生成真正的Advisor对象,最后放入缓存。

  可以看看isAspect方法是如何判断的:


@Override
	public boolean isAspect(Class<?> clazz) {
		return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
	}
	private boolean hasAspectAnnotation(Class<?> clazz) {
		return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
	}

  逻辑很清晰,主要就是看有没有Aspect注解。 但是这里要注意,这个buildAspectJAdvisors方法通常不是在这里调用的(”这里“的意思是postProcessAfterInitialization的流程)。回到AnnotationAwareAspectJAutoProxyCreator继承关系图中,它也实现了InstantiationAwareBeanPostProcessor接口,同样在其父类AbstractAutoProxyCreator中实现了postProcessBeforeInstantiation方法,这个方法会在对象实例化(不是初始化)之前调用,在该方法的逻辑里通常会首先触发buildAspectJAdvisors方法的执行,执行之后会把结果缓存起来。

  好了,再回到findEligibleAdvisors方法,上面代码已经贴了,这里就不贴了。获取到Advisor列表之后,要从中找到能用于指定类的Advisor列表,然后返回。接下来就要为指定的对象创建代理对象了,也就是AbstractAutoProxyCreator类的createProxy方法:


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

		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		for (Advisor advisor : advisors) {
			proxyFactory.addAdvisor(advisor);
		}

		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		return proxyFactory.getProxy(getProxyClassLoader());
	}

  代理对象是由ProxyFactory代理工厂创建的,我们先看看这个工厂是如何创建代理对象的,也就是proxyFactory.getProxy方法:


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

  createAopProxy方法会返回一个AopProxy,该方法定义在ProxyFactory的父类ProxyCreatorSupport中:


public class ProxyCreatorSupport extends AdvisedSupport {
	private AopProxyFactory aopProxyFactory;
	public ProxyCreatorSupport() {
		//设置默认的代理工厂DefaultAopProxyFactory
		this.aopProxyFactory = new DefaultAopProxyFactory();
	}
	public AopProxyFactory getAopProxyFactory() {
		//获取代理工厂,默认就是DefaultAopProxyFactory
		return this.aopProxyFactory;
	}

	protected final synchronized AopProxy createAopProxy() {
		//先获取代理工厂,然后调用工厂的createAopProxy方法创建AopProxy
		return getAopProxyFactory().createAopProxy(this);
	}
}

  上面贴出了关键代码,getAopProxyFactory默认返回的是一个DefaultAopProxyFactory工厂类,来看看DefaultAopProxyFactory的createAopProxy方法:


public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			Class<?> targetClass = config.getTargetClass();
			if (targetClass.isInterface()) {
				return new jdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

  代码中有一些代理配置的判断,这里不用关心。可以看到它提供了两个AopProxy,分别是基于JDK的JdkDynamicAopProxy和基于cglib的ObjenesisCglibAopProxy。由于JDK提供的动态代理实现最终生成的代理类默认会继承Proxy类,实现被代理类实现的接口,因为Java是单继承,所以只能通过接口实现,也就限制了要使用JDK提供的动态代理,必须要基于接口。而使用cglib基于字节码的改造则没有这个限制,所以Spring提供了这两种方式,根据被代理类的实际情况来选择。

  关于每个AopProxy是如何创建代理类的,这里就先不跟了~

总结

  总的来说,动态代理是实现AOP的重要手段,Spring提供的动态代理主要依靠其提供的BeanPostProcessor,也称之为后置处理器。除了BeanPostProcessor之外,还有InstantiationAwareBeanPostProcessor(也继承了BeanPostProcessor),它们会在bean的生命周期的特定阶段被调用,以开放给开发者处理和调整对象的入口或者手段。动态代理依托后置处理器,在后置处理器的逻辑中使用AopProxy创建了被代理对象的代理类,然后代替原有类存入Spring的bean工厂中,之后根据beanName获取的实例对象就不再是原对象实例,而是代理类。而AopProxy是由AopProxyFactory接口生成,目前该接口只有DefaultAopProxyFactory实现类,其提供了两种AopProxy,分别基于原生JDK提供的动态代理和cgib,根据实际情况选择。

到此这篇关于Spring源码学习之动态代理实现流程的文章就介绍到这了,更多相关Spring动态代理实现内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Spring源码学习之动态代理实现流程

本文链接: https://lsjlt.com/news/122486.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Spring源码学习之动态代理实现流程
    注:这里不阐述Spring和AOP的一些基本概念和用法,直接进入正题。 流程   Spring所管理的对象大体会经过确定实例化对象类型、推断构造方法创建对象...
    99+
    2024-04-02
  • Spring源码如何实现动态代理
    小编给大家分享一下Spring源码如何实现动态代理,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!注:这里不阐述Spring和AOP的一些基本概念和用法,直接进入正题。流程  Spring所管理的对象大体会经过确定实例化对象...
    99+
    2023-06-14
  • Spring框架学习之Spring @Autowired实现自动装配的代码
    学习自动装配之前,讲一个概念:Component,即组件。组件你也可以理解为bean对象,只不过通常Component的组成会稍微复杂一些,比如,一个组件里面会引用一个或多个别的be...
    99+
    2024-04-02
  • Webpack学习之动态import原理及源码分析
    目录前言原理分析源码分析及实现如何动态加载远程模块__webpack_require__.e 函数的实现如何执行远程模块?总结前言 在开始之前,先给我的mini-react打个广告。...
    99+
    2023-05-17
    Webpack动态import 动态import
  • Spring Core动态代理的实现代码
    目录1.设计原理2.ProxyFactory (Spring-Core)2.1 JdkDynamicAopProxy2.2 CglibAopProxy2.3 主要源码部分1.设计原理...
    99+
    2024-04-02
  • Spring源码解析之循环依赖的实现流程
    目录前言循环依赖实现流程前言 上篇文章中我们分析完了Spring中Bean的实例化过程,但是没有对循环依赖的问题进行分析,这篇文章中我们来看一下spring是如何解决循环依赖的实现。...
    99+
    2024-04-02
  • java动态代理实现代码
    目录1、代理模式2、动态代理3、原理研究4、应用5、总结1、代理模式 代理模式是常用的设计模式之一,也是开发中常见的设计模式。 简单的描述一下,代理模式就是将实现类隔离开,比如你想给...
    99+
    2024-04-02
  • Android学习教程之下拉刷新实现代码(11)
    本文实例为大家分享了Android下拉刷新的具体代码,供大家参考,具体内容如下 MainActivity.java代码: package siso.refreshablev;...
    99+
    2022-06-06
    android学习 程之 教程 Android
  • Java实现动态代理的实例代码
    目录前言静态代理 动态代理 CGLib实现动态代理 总结前言 动态代理在Java中有着广泛的应用,比如Spring AOP、Hibernate数据查询、测试框架的后端mock、RPC...
    99+
    2024-04-02
  • Mybatis4 之Mybatis动态sql的实现代码
    1.什么是动态SQL 传统的使用JDBC的方法,相信大家在组合复杂的的SQL语句的时候,需要去拼接,稍不注意哪怕少了个空格,都会导致错误。Mybatis的动态SQL功能正是为了解决这种问题, 其通过 if...
    99+
    2024-04-02
  • Spring整合Mybatis具体代码实现流程
    目录原始方式读取mybatis配置文件,获取SqlSession SqlSessionFactory 等 package com.atguigu.rj1192.zyk; import...
    99+
    2024-04-02
  • Vue源码学习之响应式是如何实现的
    目录前言一、一个响应式系统的关键要素1、如何监听数据变化2、如何进行依赖收集——实现 Dep 类3、数据变化时如何更新——实现 Watcher 类二、虚拟 DOM 和 diff1、虚...
    99+
    2024-04-02
  • Spring动态代理实现日志功能详解
    代理模式(Proxy)是通过代理对象访问目标对象,这样可以在目标对象基础上增强额外的功能,如添加权限,访问控制和审计等功能。 1.自定义业务接口 package com.haij...
    99+
    2024-04-02
  • 如何在Spring框架中实现动态代理
    这篇文章给大家介绍如何在Spring框架中实现动态代理,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。动态代理,是一种通过运行时操作字节码,以达到增强类的功能的技术,也是Spring AOP操作的基础,关于AOP的内容,...
    99+
    2023-05-31
    spring 动态代理
  • Java动态代理实现_动力节点Java学院整理
    动态代理作为代理模式的一种扩展形式,广泛应用于框架(尤其是基于AOP的框架)的设计与开发,本文将通过实例来讲解Java动态代理的实现过程。通常情况下,代理模式中的每一个代理类在编译之后都会生成一个class文件,代理类所实现的接口和所代理的...
    99+
    2023-05-31
    java 动态代理 ava
  • Java Spring AOP源码解析之事务实现原理
    目录不用Spring管理事务?编程式事务管理使用PlatformTransactionManager使用TransactionTemplate声明式事务管理使用@Transactio...
    99+
    2024-04-02
  • nginx代理实现静态资源访问的示例代码
    目录一. 目标:二. 实现效果:三. 具体配置1. nginx配置本地静态工程代理2. win10配置本地域名实现域名访问3.nginx配置页面预览路由一. 目标: 为了通过ngin...
    99+
    2024-04-02
  • Vue源码学习defineProperty响应式数据原理实现
    目录准备工作第一步 对对象进行劫持第二步 修改取值方法第三步 深度属性劫持准备工作 接上文数据初始化完成之后,就可以对数据进行劫持。Vue2中对数据进行劫持采用了一个Api叫Obje...
    99+
    2024-04-02
  • Java注解实现动态数据源切换的实例代码
    当一个项目中有多个数据源(也可以是主从库)的时候,我们可以利用注解在mapper接口上标注数据源,从而来实现多个数据源在运行时的动态切换。实现原理在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充...
    99+
    2023-05-31
    java 数据源 切换
  • python深度学习之多标签分类器及pytorch实现源码
    目录多标签分类器多标签分类器损失函数代码实现多标签分类器 多标签分类任务与多分类任务有所不同,多分类任务是将一个实例分到某个类别中,多标签分类任务是将某个实例分到多个类别中。多标签分...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作