返回顶部
首页 > 资讯 > 后端开发 > Python >spring @Lazy延迟注入的逻辑实现
  • 795
分享到

spring @Lazy延迟注入的逻辑实现

2024-04-02 19:04:59 795人浏览 安东尼

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

摘要

目录前言一、一个简单的小例子二、源码解读1. 注入2. 使用逻辑总结前言 有时候我们会在属性注入的时候添加@Lazy注解实现延迟注入,今天咱们通过阅读源码来分析下原因 一、一个简单的

前言

有时候我们会在属性注入的时候添加@Lazy注解实现延迟注入,今天咱们通过阅读源码来分析下原因

一、一个简单的小例子

代码如下:


@Service
public class NORMalService1 {

	@Autowired
	@Lazy
	private MyService myService;

	public void doSomething() {
		myService.getName();
	}
}

作用是为了进行延迟加载,在NormalService1进行属性注入的时候,如果MyService还没有生成bean也不用担心,会注入一个代理,但是在实际运行的时候,会获取spring容器中实际的MyService,在某些情况下,因为spring生命周期的原因,这个注解有大用。

二、源码解读

1. 注入

代码如下(DefaultListableBeanFactory#resolveDependency):


public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
		if (Optional.class == descriptor.getDependencyType()) {
			return createOptionalDependency(descriptor, requestingBeanName);
		}
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {
			//如果注入属性添加了@Lazy,懒加载,此时spring会根据具体类型搞个cglib代理类
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}

很明显要执行getLazyResolutionProxyIfNecessary方法,如果加了@Lazy注解,最终会执行buildLazyResolutionProxy方法


protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
		Assert.state(getBeanFactory() instanceof DefaultListableBeanFactory,
				"BeanFactory needs to be a DefaultListableBeanFactory");
		final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory();
		TargetSource ts = new TargetSource() {
			@Override
			public Class<?> getTargetClass() {
				return descriptor.getDependencyType();
			}
			@Override
			public boolean isStatic() {
				return false;
			}
			@Override
			public Object getTarget() {
				Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null);
				
				return target;
			}
			@Override
			public void releaseTarget(Object target) {
			}
		};
		ProxyFactory pf = new ProxyFactory();
		pf.setTargetSource(ts);
		Class<?> dependencyType = descriptor.getDependencyType();
		if (dependencyType.isInterface()) {
			pf.addInterface(dependencyType);
		}
		return pf.getProxy(beanFactory.getBeanClassLoader());
	}

可以看到上面这段代码,其实就是生成了一个TargetSource,然后再生成了一个代理(CGLIB或者jdk),然后作为MyService对象注入给了NormalService1。那么所谓的执行的过程中才进行获取真正的MyService对象是什么意思呢?

2. 使用逻辑

本文示例代码使用的是CGLIB代理,其实是类似的,因为注入的MyService是个CGLIB代理对象,那么在执行方法的时候,就会调用CglibaopProxy#DynamicAdvisedInterceptor#intercept方法

在这里插入图片描述

那么此处其实调用的就是上面的


Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null);

这个方法就不用认真看了,主要功能就是从Spring容器中找到MyService。
在之前讲@Autowired原理和@Resource注入原理的时候解释过了,不清楚的可以看专栏里其他文章。
拿出来之后会发现,咱们拿到的target对象还是一个CGLIB增加的对象

在这里插入图片描述

那么当执行方法逻辑时

在这里插入图片描述

由于target是CGLIB对象,会再次进入到CglibAopProxy#DynamicAdvisedInterceptor#intercept方法。
此时拿到的target对象类型就不同了

在这里插入图片描述

是我们代理之前的target对象,此时再次进行invoke的时候,就会进行动态代理的一般逻辑,先查找该方法匹配的所有advice,然后依次调用,最终调用target本身对于方法的执行。

总结

所以可以发现其实@Lazy只不过是给spring的代理对象proxy再进行了一次proxy,只不过没有在注入的时候,就获取到对象,而是借用了方法invoke时通过proxy的intercept方法getTarget,然后进行方法调用,延迟了对象的注入。之后每次调用的时候都需要从Spring容器中获取到原生的proxy对象。

在这里插入图片描述

到此这篇关于spring @Lazy延迟注入的逻辑实现的文章就介绍到这了,更多相关spring @Lazy延迟注入内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: spring @Lazy延迟注入的逻辑实现

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

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

猜你喜欢
  • spring @Lazy延迟注入的逻辑实现
    目录前言一、一个简单的小例子二、源码解读1. 注入2. 使用逻辑总结前言 有时候我们会在属性注入的时候添加@Lazy注解实现延迟注入,今天咱们通过阅读源码来分析下原因 一、一个简单的...
    99+
    2024-04-02
  • Java Spring @Lazy延迟注入源码案例详解
    前言 有时候我们会在属性注入的时候添加@Lazy注解实现延迟注入,今天咱们通过阅读源码来分析下原因 一、一个简单的小例子 代码如下: @Service public class ...
    99+
    2024-04-02
  • C#使用Lazy<T>实现对客户订单的延迟加载
    "延迟加载"是指在需要的时候再加载数据。比如获得一个Customer信息,并不会把该Customer的Orders信息一下加载出来,当需要显示Orders的时候再...
    99+
    2024-04-02
  • Spring Boot与RabbitMQ结合实现延迟队列的示例
    背景何为延迟队列?顾名思义,延迟队列就是进入该队列的消息会被延迟消费的队列。而一般的队列,消息一旦入队了之后就会被消费者马上消费。场景一:在订单系统中,一个用户下单之后通常有30分钟的时间进行支付,如果30分钟之内没有支付成功,那么这个订单...
    99+
    2023-05-30
    spring boot rabbitmq
  • SpringBoot实现网站的登陆注册逻辑记录
    目录技术列表:用户登录逻辑:用户注册逻辑:参考文献:总结该文章主要是为了整理之前学习项目中的知识点,并进行一定程度的理解。 技术列表: SpringBoot MyS...
    99+
    2024-04-02
  • Python赋值逻辑的实现
    目录摘要:第一章 引例第二章 Python 的“反直觉”第三章 回答第一章的问题摘要: 如果你学过 C 语言,那么当你初见 Python 时可能会觉得 Pyt...
    99+
    2023-02-22
    Python赋值逻辑 Python赋值
  • Redis延迟队列和分布式延迟队列的简答实现
            最近,又重新学习了下Redis,Redis不仅能快还能慢,简直利器,今天就为大家介绍一下Redi...
    99+
    2024-04-02
  • Android实现简易登陆注册逻辑的实例代码
    大家好,今天给大家带来Android制作登录和注册功能的实现,当我们面临制作登录和注册功能的实现时,我们需要先设计登录界面的布局和注册界面的布局,做到有完整的思路时才开始实现其功能效...
    99+
    2024-04-02
  • C++实现延迟的方法详解
    目录1、stl方式2、用boost实现, 没有用过3、sleep知识补充1、stl方式 std::this_thread::sleep_for(std::chrono::millis...
    99+
    2022-12-27
    C++实现延迟 C++延迟
  • Go+Kafka实现延迟消息的实现示例
    目录前言原理简单的实现生产者延迟服务消费者改进点通用的延迟服务生产者负责延迟服务总结前言 延迟队列是一个非常有用的工具,我们经常遇到需要使用延迟队列的场景,比如延迟通知,订单关闭等等...
    99+
    2024-04-02
  • 基于spring @Cacheable 注解的spel表达式解析执行逻辑
    目录直接进入主题 跟随spring的调用链直接看 @Cacheable 注解就可以了接下来看 key获取是在哪里没有任何逻辑就是一个组装了解一下@Cacheable的拦截顺序接下来看...
    99+
    2024-04-02
  • PyTorch实现多维度特征输入逻辑回归
    目录一、实现过程1、准备数据2、设计模型4、训练过程5、结果展示二、参考文献一、实现过程 1、准备数据 本文数据采取文献[1]给出的数据集,该数据集前8列为特征,最后1列为标签(0/...
    99+
    2024-04-02
  • PostgreSQL的逻辑复制怎么实现
    在 PostgreSQL 中,逻辑复制是通过订阅和发布的方式实现的。下面是实现逻辑复制的步骤: 创建发布者(publisher):...
    99+
    2024-04-02
  • Android实现延迟的几种方法小结
    本文实例总结了Android实现延迟的几种方法。分享给大家供大家参考,具体如下: 一、通过Thread new Thread(){ public void run(){ sl...
    99+
    2022-06-06
    小结 方法 Android
  • 基于Redis延迟队列的实现代码
    使用场景 工作中大家往往会遇到类似的场景: 1.对于红包场景,账户 A 对账户 B 发出红包通常在 1 天后会自动归还到原账户。 2.对于实时支付场景,如果账户 A 对商户 S 付款...
    99+
    2024-04-02
  • rust延迟5秒锁屏的实现代码
    先给大家介绍下rust延迟5秒锁屏的实现代码: main.rs #![windows_subsystem = "windows"] use std::process::Command...
    99+
    2024-04-02
  • android实现简易登录注册界面及逻辑设计
    本文实例为大家分享了android实现登录注册界面及逻辑设计,供大家参考,具体内容如下 1. 第一步 新建文件(相信各位码农一定会这一步)略。 2. 第二步 登录注册界面设计 登录界...
    99+
    2024-04-02
  • Android程序锁的实现以及逻辑
    本项目是一个比较有趣的项目源码,可以给其他项目加锁,程序锁的原理是一个“看门狗”的服务定时监视顶层activity,如果activity对应的包名是之前上锁的应用程序的,则弹出...
    99+
    2022-06-06
    Android
  • PostgreSQL中create_plan的实现逻辑是什么
    本篇内容主要讲解“PostgreSQL中create_plan的实现逻辑是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中create_...
    99+
    2024-04-02
  • Spark SQL的整体实现逻辑解析
    1、sql语句的模块解析    当我们写一个查询语句时,一般包含三个部分,select部分,from数据源部分,where限制条件部分,这三部...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作