乐趣区

关于java:一不小心你就掉进了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();
    }

}

测试后果

生效起因

  这个十分好了解,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");
    }

}

启动后果:

  通过观察启动后果,能够看到 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");
    }

}

启动后果:

  通过观察启动后果,能够看到 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");
    }

}

启动后果:

  这个时候你会发现,貌似这个后果不对呀。下面提到,@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 无效。

结尾

  如果感觉对你有帮忙,能够多多评论,多多点赞哦,也能够到我的主页看看,说不定有你喜爱的文章,也能够顺手点个关注哦,谢谢。

  我是不一样的科技宅,每天提高一点点,体验不一样的生存。咱们下期见!

退出移动版