前言
书接上回,之前咱们有聊到 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 有用。
结束
假如觉得对你有协助,能够多多谈论,多多点赞哦,也能够到我的主页看看,说不定有你喜爱的文章,也能够随手点个关注哦,谢谢。
我是不相同的科技宅,每天进步一点点,体会不相同的生活。咱们下期见!