前言

一不小心,你就掉进了Spring延迟初始化的坑!

  书接上回,之前咱们有聊到 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();
    }
}

测验成果

一不小心,你就掉进了Spring延迟初始化的坑!

失效原因

  这个非常好了解,myService 并没有装备@Lazy,所以在发动的时分会被初始化。因为 myService 依靠 myBean,myBean 就会被注入。所以这意味着 myBean 要能正常被注入,就得被初始化,假如不初始化就会发动失败。这也便是形成 myBean 推迟初始化失效的原因。

解决方法

  解决方法很简单,在依靠到的地方都装备上@Lazy,避免呈现被非推迟初始化的 Bean 注入了。

坑 2. 推迟加载失效:Bean 的效果域错误装备

  @Lazy 注解只对单例(Singleton)效果域的 Bean 有用。默许情况下,Spring 的 Bean 效果域是单例,假如将 Bean 的效果域设置为其他效果域(如原型、恳求、会话等)的是不起效果的。

代码演示:

  1. 默许不做任何装备。
@Component
public class MyBean {
    public MyBean() {
        System.out.println("My bean init success.");
    }
    public void exec() {
        System.out.println("exec suc");
    }
}

发动成果:

一不小心,你就掉进了Spring延迟初始化的坑!

  通过调查发动成果,能够看到 myBean 在发动的时分被初始化了。

  1. 加上@Lazy
@Lazy
@Component
public class MyBean {
    public MyBean() {
        System.out.println("My bean init success.");
    }
    public void exec() {
        System.out.println("exec suc");
    }
}

发动成果:

一不小心,你就掉进了Spring延迟初始化的坑!

  通过调查发动成果,能够看到 myBean 并没有初始化,说明@Lazy生效了。

  1. 设置 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");
    }
}

发动成果:

一不小心,你就掉进了Spring延迟初始化的坑!

一不小心,你就掉进了Spring延迟初始化的坑!

  这个时分你会发现,貌似这个成果不对呀。上面说到,@Lazy 注解只对单例(Singleton)效果域的 Bean 有用。可是我已经将 Scope 改为 prototype。 按理来应该是这样:

一不小心,你就掉进了Spring延迟初始化的坑!

  控制台会输出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");
    }
}

发动成果:

一不小心,你就掉进了Spring延迟初始化的坑!

  发现和单独装备@Lazy的效果是相同,并没有被初始化。

一不小心,你就掉进了Spring延迟初始化的坑!

定论

  当 bean 效果域是 prototype 时,这些 bean 每次在需求时,都会按需实例化和初始化,因而它们本质上是推迟始化的。所以给他们装备@Lazy是没有意义的。

  在上面的案例,呈现这样的情况是因为,在发动的时分 myBean 并没有,被其他 Bean 依靠和运用。所以表现出和@Lazy相同的效果。误以为当 Bean 效果域是 prototype 时,@Lazy能够生效。

总结

  因为 spring bean 的默许效果域是:singleton。所以在发动的时分 bean 会被初始化,假如被标记了@Lazy,会推迟初始化,可是假如被非懒加载的 Bean 注入了,@Lazy会失效。而且@Lazy注解只对单例 singleton 效果域的 Bean 有用。

结束

  假如觉得对你有协助,能够多多谈论,多多点赞哦,也能够到我的主页看看,说不定有你喜爱的文章,也能够随手点个关注哦,谢谢。

  我是不相同的科技宅,每天进步一点点,体会不相同的生活。咱们下期见!