前言
书接上回,之前咱们有聊到 Spring 的提早初始化机制,是什么,有什么作用。明天跟各位大佬分享一下,我在应用 Spring 提早初始化踩过的一些坑。
List< 坑 > 坑列表 = new ArrayList<>(2);
首先,让咱们回顾一下 Spring 提早初始化的概念。在 Spring 中,提早初始化指的是将 Bean 的实例化推延到第一次被应用时,而不是在应用程序启动时就立刻创立所有的 Bean。这种提早加载的机制能够进步应用程序的性能和资源利用率。
坑 1. 提早加载生效,被非提早初始化的 Bean 注入了。
代码演示:
@Lazy
@Component
public class MyBean {public MyBean() {System.out.println("My bean init success.");
}
}
1、应用构造函数注入
@Service
public class MyService {
private MyBean myBean;
public MyService(MyBean myBean) {this.myBean = myBean;}
public void exec() {System.out.println("exec suc");
}
}
2、@Resource 注入
@Service
public class MyService {
@Resource
private MyBean myBean;
public void exec() {System.out.println("exec suc");
}
}
3、@Autowired 注入
@Service
public class MyService {
private MyBean myBean;
@Autowired
public void setMyBean(MyBean myBean) {this.myBean = myBean;}
public void exec() {myBean.exec();
}
}
测试后果
生效起因
这个十分好了解,myService 并没有配置@Lazy
,所以在启动的时候会被初始化。因为 myService 依赖 myBean,myBean 就会被注入。所以这意味着 myBean 要能失常被注入,就得被初始化,如果不初始化就会启动失败。这也就是造成 myBean 提早初始化生效的起因。
解决办法
解决办法很简略,在依赖到的中央都配置上@Lazy
,避免出现被非提早初始化的 Bean 注入了。
坑 2. 提早加载生效:Bean 的作用域谬误配置
@Lazy 注解只对单例(Singleton)作用域的 Bean 无效。默认状况下,Spring 的 Bean 作用域是单例,如果将 Bean 的作用域设置为其余作用域(如原型、申请、会话等)的是不起作用的。
代码演示:
- 默认不做任何配置。
@Component
public class MyBean {public MyBean() {System.out.println("My bean init success.");
}
public void exec() {System.out.println("exec suc");
}
}
启动后果:
通过观察启动后果,能够看到 myBean 在启动的时候被初始化了。
- 加上
@Lazy
@Lazy
@Component
public class MyBean {public MyBean() {System.out.println("My bean init success.");
}
public void exec() {System.out.println("exec suc");
}
}
启动后果:
通过观察启动后果,能够看到 myBean 并没有初始化,阐明 @Lazy
失效了。
- 设置 scope
@Lazy
@Component
@Scope("prototype")
public class MyBean {public MyBean() {System.out.println("My bean init success.");
}
public void exec() {System.out.println("exec suc");
}
}
启动后果:
这个时候你会发现,貌似这个后果不对呀。下面提到,@Lazy 注解只对单例(Singleton)作用域的 Bean 无效。然而我曾经将 Scope 改为 prototype。按理来应该是这样:
控制台会输入My bean init success.
,然而事实就是没有。那么这是为什么呢?
起因剖析
因为是减少了 @Scope("prototype")
,发现后果不合乎预期,那咱们就从它动手。咱们先回顾一下 Spring Bean 的作用域相干的常识。当 Spring Bean 作用域为 prototype
时,每次获取 Bean 时都会从新创立一个实例。
换句话说,也就意味着,当的 Bean 作用域为 prototype 时,Bean 在被应用的才会被初始化,并且每个 Bean 都是全新的。
诶,在应用的时候被初始化,这不就是提早初始化吗。改下代码测试一下:
去掉@Lazy
:
@Component
@Scope("prototype")
public class MyBean {public MyBean() {System.out.println("My bean init success.");
}
public void exec() {System.out.println("exec suc");
}
}
启动后果:
发现和独自配置 @Lazy
的成果是一样,并没有被初始化。
论断
当 bean 作用域是 prototype 时,这些 bean 每次在须要时,都会按需实例化和初始化,因而它们实质上是提早始化的。所以给他们配置 @Lazy
是没有意义的。
在下面的案例,呈现这样的状况是因为,在启动的时候 myBean 并没有,被其余 Bean 依赖和应用。所以体现出和 @Lazy
一样的成果。误以为当 Bean 作用域是 prototype 时,@Lazy
能够失效。
总结
因为 spring bean 的默认作用域是:singleton。所以在启动的时候 bean 会被初始化,如果被标记了 @Lazy
,会提早初始化,然而如果被非懒加载的 Bean 注入了,@Lazy
会生效。并且 @Lazy
注解只对单例 singleton 作用域的 Bean 无效。
结尾
如果感觉对你有帮忙,能够多多评论,多多点赞哦,也能够到我的主页看看,说不定有你喜爱的文章,也能够顺手点个关注哦,谢谢。
我是不一样的科技宅,每天提高一点点,体验不一样的生存。咱们下期见!