spring @lazy注解的使用

在spring中@lazy注解表达延迟的含义,但在不同情况下,这里的延迟并不是同一层意思。下面将描述我发现的两层含义。

1. 延迟初始化bean

​ 首先我们知道,容器启动之前会扫描所有的class文件,并将需要加载到容器中的类,整理成BeanDefinition存储。容器启动时将依次将BeanDefinition构建成bean,构建过程中同时解决依赖注入和循环引用的问题。

​ 但并不是所有的BeanDefinition都会被构建成bean,观察源码中下面方法 org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

​ 此为容器启动过程时,从BeanDefinition构建成bean的入口。这里有三种情况不会进行初始化,

  1. 非抽象类

  2. 是单例模式的bean

  3. 非Lazy模式的

    所以这里就体现了Lazy的第一层含义,添加Lazy的注解的bean不会在容器启动时主动创建。

@Override
public void preInstantiateSingletons() throws BeansException {if (logger.isTraceEnabled()) {logger.trace("Pre-instantiating singletons in " + this);}// Iterate over a copy to allow for init methods which in turn register new bean definitions.// While this may not be part of the regular factory bootstrap, it does otherwise work fine.List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {if (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {FactoryBean<?> factory = (FactoryBean<?>) bean;boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}}else {getBean(beanName);}}}

有两种方式添加Lazy注解,一种直接在类上加@Lazy注解。一种是如果使用@Bean模式创建的bean,在方法上添加@Lazy注解。

​ 但这里Lazy的含义仅仅是不在容器启动时主动生成bean,但可能会被动生成bean。如果bean A被 bean B依赖,A是lazy的,在启动时虽然A不会被主动创建,但在创建B时,需要依赖A,此时A就会被动的创建。

​ 所以仅对某个bean的创建添加Lazy意义不是特别大,因为bean相互之间都是有依赖关系的,即使不主动创建也会被被动创建!

2. 延迟依赖注入

第二种Lazy的方式就比较有用了,如下面的例子。

@Componentpublic class A{}public class B{   @Lazy@Resourceprivate A a;}

​ 这个例子中B依赖A。在构建B时需要将A注入,但是我们添加了@Lazy注解,注入时并不会真的从容器中查找A,而是注入一个A的动态代理。在运行阶段,调用动态代理类的方法时,才会真的从容器中查找A。

​ 下面代码是 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

的内部类,这里是负责依赖注入时查找依赖的部分, getResourceToInject 方法里进行判断,如我上面讲的,如果是lazy的依赖则会生成动态代理,否则才会从容器中真实获取。

​ lazyLookup 变量的在 ResourceElement 的构造方法里获取的。

private class ResourceElement extends LookupElement {private final boolean lazyLookup;public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {super(member, pd);Resource resource = ae.getAnnotation(Resource.class);String resourceName = resource.name();Class<?> resourceType = resource.type();this.isDefaultName = !StringUtils.hasLength(resourceName);if (this.isDefaultName) {resourceName = this.member.getName();if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {resourceName = Introspector.decapitalize(resourceName.substring(3));}}else if (embeddedValueResolver != null) {resourceName = embeddedValueResolver.resolveStringValue(resourceName);}if (Object.class != resourceType) {checkResourceType(resourceType);}else {// No resource type specified... check field/method.resourceType = getResourceType();}this.name = (resourceName != null ? resourceName : "");this.lookupType = resourceType;String lookupValue = resource.lookup();this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());Lazy lazy = ae.getAnnotation(Lazy.class);this.lazyLookup = (lazy != null && lazy.value());}@Overrideprotected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :getResource(this, requestingBeanName));}
}

3.配合使用

综上所述,如果将@Lazy 添加在类上,虽不会主动创建,但被依赖时还会被创建。

如果将@Lazy添加到注入的字段上,可以推迟注入的时间到运行时,但依赖已经被创建了,只是没注入而已,该耗费的时间也已经耗费了。

将两者配合使用,即可达到运行时再创建需要的对象,如果不需要可一直不创建。

spring @lazy注解的使用相关推荐

  1. Spring 通过 @Lazy 注解解决构造方法循环依赖问题

    什么是循环依赖? 先定义两个类 Apple.Orange,如下所示: @Component public class Apple{@Autowiredprivate Orange orange; }@ ...

  2. Spring中的 @Lazy注解

    Spring IoC (ApplicationContext) 容器一般都会在启动的时候实例化所有单实例 bean . 如果我们想要 Spring 在启动的时候延迟加载 bean,即在调用某个 bea ...

  3. 【Spring】@Lazy注解

    今天主要从以下几方面来介绍一下@Lazy注解 @Lazy注解是什么 @Lazy注解怎么使用 1.@Lazy注解是什么 @Lazy注解用于标识bean是否需要延迟加载,源码如下: @Target({El ...

  4. Spring系列之Spring常用注解总结

    参看博客:https://www.cnblogs.com/xiaoxi/p/5935009.html 传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺 ...

  5. Spring常用注解总结

    传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点: 1.如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大:如果按需求分开.xml文 ...

  6. Spring5源码 - Spring IOC 注解复习

    文章目录 Pre xml配置文件 JavaConfig @CompentScan 在配置类上写@CompentScan注解来进行包扫描 excludeFilters includeFilters @C ...

  7. Spring Boot 注解大全,一键收藏了!

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达今日推荐:2020年7月程序员工资统计,平均14357元,又跌了,扎心个人原创100W+访问量博客:点击前往,查看更多 Sp ...

  8. spring系列-注解驱动原理及源码-bean组件注册

    目录 一.环境初始化 1.环境准备 二.bean的手动注入 1.xml方式注入bean 2.使用@Configuration&@Bean方式注入bean 三.自动扫描注册组件及bean 1.使 ...

  9. spring autowired idea都匹配上了_你清楚这几个Spring常用注解吗?

    作者:平凡希http://cnblogs.com/xiaoxi/p/5935009.html 传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点: 如 ...

  10. spring的注解开发@Component @Bean @Value @Autowired、@Qualifier @PropertySource @Configuration

    spring的注解开发 启动注解功能 启动注解功能 ⚫ 启动注解扫描,加载类中配置的注解项 ⚫ 说明: ◆ 在进行包所扫描时,会对配置的包及其子包中所有文件进行扫描 ◆ 扫描过程是以文件夹递归迭代的形 ...

最新文章

  1. 程序江湖:第十四章 离开让男人成长
  2. VOFM、Copy Control与合并开票
  3. QT的QDesignerPropertySheetExtension类的使用
  4. winform-日记
  5. 人脸检测(一)--综述
  6. [2018.07.10 T1]叠盒子
  7. 出海业务网络加速方案技术能力详解
  8. 玉柴spn码故障对照表_玉柴共轨电喷发动机故障码一览表
  9. 实验室设备管理系统(C语言实现)
  10. 计算机网络课程论文:《浅谈交换机、路由器》
  11. 一个技术创业者的2018年度回顾和总结 | 掘金年度征文
  12. jsr基本使用@valid和@validation
  13. 微型计算机2019年年度盘点,「2019 IT产业市场回顾」性能堆砌、轴之战再起、多声道普及!2019年游戏外设市场年终盘点...
  14. linux越狱时手机怎么进入dfu,iOS详细越狱步骤 进入DFU模式_iPhone资讯_太平洋电脑网PConline...
  15. python-数据分析--案例分析:美国各州人口数据分析
  16. 一款超方便超强大的16进制编辑器软件-HxD
  17. ibm服务器开不了机维修,IBM X3500服务器故障开不了机
  18. Java容器的常用组件
  19. html_blog 84-109
  20. 不使用strcpy函数,编程实现把b字符串复制到a中的程序(字符串长度限制在100个字符以内)。以下是部分代码,请完成并提交

热门文章

  1. 某天的零点时刻0:0:0 和截至时刻23:59:59
  2. 正则表达式之提取数字
  3. Windows系统设置局域网共享(无密码+有密码)
  4. python镜像源地址
  5. STM32MP157 三角函数运算花费时间比较
  6. 一起变装吧服务器维护,2020年1月16日维护预览
  7. 使用给定的整数n,编写一个程序生成一个包含(i, i*i)的字典,该字典包含1到n之间的整数(两者都包含)。假设向程序输入:5则输出为:{1:1, 2:4, 3:9, 4:16, 5:25}
  8. echars折线图y轴自定义数值会被转换为整数的问题
  9. cvpr 2018 image caption generation论文导读(含workshop)
  10. 分槽ALOHA协议仿真