Spring Boot 学习系列(09)—自定义Bean的顺序加载

此文已由作者易国强授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

Bean 的顺序加载

  • 有些场景中,我们希望编写的Bean能够按照指定的顺序进行加载。比如,有UserServiceBean和OrderServiceBean,我们需要在OrderServiceBean中调用UserServiceBean,获取其提供的一些数据信息。针对这一场景,通常来说,有这么几种方式:
  • 1、将UserServiceBean封装成一个服务类(如采用@Service注解),然后在OrderServiceBean中引入这个服务类,直接调用即可,简单快捷。示例如下所示:
      @Service("userServiceBean")  public class UserServiceBean {      public String print() {
              System.out.println("this is UserServiceBean print");          return "print ok";
          }
      }  @Service("orderServiceBean")  public class OrderServiceBean {      @Resource
          UserServiceBean userServiceBean;      public void invoke(){
              String ret = userServiceBean.print();
              System.out.println("this is OrderServiceBean invoke " + ret );
          }
      }
  • 2、然而有些时候,我们的xxxServiceBean是没有封装成服务的,只是作为一个单纯的Bean注入到Spring容器中。这个时候如果我们需要使用这个Bean实例,通常会考虑直接从ApplicationContext中以getBean("xxxServiceBean")的方式获取。
    • 在传统的项目中,我们一般都会在xml配置文件中注入xxxServiceBean,这个时候Spring容器会依据xml中代码编写的顺序依次加载各个Bean,示例如下所示:

      <!-- 按代码编写顺序依次加载 --><!-- 订单服务Bean --><bean id="orderServiceBean" class="com.example.a.OrderServiceBean"></bean><!-- 演示服务--><bean id="depService" class="com.example.a.DepService"></bean><!-- 演示服务--><bean id="demoService" class="com.example.a.OtherDemoServiceImpl"></bean><!-- 用户服务Bean--><bean id="userServiceBean" class="com.example.a.UserServiceBean"></bean>

      在各构造函数中加入日志输出可发现,会按照顺序依次加载。如下图所示:

![image](https://github.com/siyuyifang/image/blob/master/spring-boot/9/9-1.png?raw=true)- 如果我们在OrderServiceBean中有调用UserServiceBean,那么UserServiceBean则会优先于DepService和OtherDemoServiceImpl加载,调用代码如下:

```public class OrderServiceBean {public OrderServiceBean() {
    System.out.println("OrderServiceBean constructor init.");
    UserServiceBean  userServiceBean =  SpringContextHolder.getBean("userServiceBean");
    String ret = userServiceBean.print();
    System.out.println("this is OrderServiceBean invoke " + ret );
}
}
```
这个时候观察加载的顺序如下图所示:

![image](https://github.com/siyuyifang/image/blob/master/spring-boot/9/9-2.png?raw=true)- 在Spring Boot项目中,我们一般用@Configuration + @Bean注解的方式来替代xml中Bean的注入,这个时候定义Bean的加载顺序也很简单,在同一个配置类中,也是按照代码的编写顺序加载实例化的。示例如下所示:

```@Configurationpublic class MyConfigs {@Bean("userServiceBean")public UserServiceBean userServiceBean(){    return new UserServiceBean();
}@Bean("orderServiceBean")public OrderServiceBean orderServiceBean(){    return new OrderServiceBean();
}
```
  • 有这么一个使用场景,如果UserServiceBean 采用@Bean + @Configuration的方式注入,而OrderServiceBean采用@Service注解的形式提供服务,同时在OrderServiceBean中仍然通过ApplicationContext的getBean()方式获取UserServiceBean的示例,那么在编译时候会报如下错误:

其中SpringContextHolder.java的代码如下所示:

@Component("springContextHolder")public class SpringContextHolder implements ApplicationContextAware {    private static ApplicationContext applicationContext;    /**
     * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextHolder.applicationContext = applicationContext;
    }    /**
     * 取得存储在静态变量中的ApplicationContext.
     */
    public static ApplicationContext getApplicationContext() {
        checkApplicationContext();        return applicationContext;
    }    /**
     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    @SuppressWarnings("unchecked")    public static <T> T getBean(String name) {
        checkApplicationContext();        return (T) applicationContext.getBean(name);
    }    private static void checkApplicationContext() {        if (applicationContext == null) {            throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextUtil");
        }
    }
}
  • 这个时候,我们需要在OrderServiceBean类前加入如下注解,表示此Bean依赖于springContextHolder实例的加载,代码示例如下所示,再次编译通过。
@Service
@DependsOn("springContextHolder")public class OrderServiceBean {    public OrderServiceBean() {
        System.out.println("OrderServiceBean constructor init.");
        UserServiceBean  userServiceBean =  SpringContextHolder.getBean("userServiceBean");
        String ret = userServiceBean.print();
        System.out.println("this is OrderServiceBean invoke " + ret );
    }

}
  • 此外,如果需要指定一个Bean A 先于 Bean B加载,那么可以在Bean B类前加入@DependsOn("beanA"),指定依赖加载顺序。
  • 不足之处,欢迎指正,谢谢~

免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击

相关文章:
【推荐】 基于开源,强于开源,轻舟微服务解决方案深度解读
【推荐】 当Shell遇上了NodeJS

原文地址:https://www.cnblogs.com/zyfd/p/9887318.html

时间: 2024-10-07 13:14:46

Spring Boot 学习系列(09)—自定义Bean的顺序加载的相关文章

Spring Boot 学习系列(08)—自定义servlet、filter及listener

此文已由作者易国强授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 传统的filter及listener配置 在传统的Java web项目中,servlet.filter和listener的配置很简单,直接在web.xml中按顺序配置好即可,程序启动时,就会按照你配置的顺序依次加载(当然,web.xml中各配置信息总的加载顺序是context-param -> listener -> filter -> servlet),项目搭建完成后,估计一般新来的开发同学没啥

spring boot学习系列(一)

spring boot开发第一个应用程序 1.spring boot是什么? 2.spring boot容易上手吗? 写这篇文章技术文章,主要是记录日常的学习以及理解. 我们重新认识一下spring 假设你受命使用spring开发一个简单的hello word的web程序. 你该做什么?我能想到一些基本的需要. 1.一个项目结构,假设使用maven构建的项目,需要引入一些jar包 2.一个web.xml的入口启动文件.里面配置一些启动项 3.一个类控制器,假设使用spring mvc,需要写一个

spring boot学习系列(二)

spring boot多环境配置以及yml配置文件 1.平时项目中,我们可能需要到配置生产环境,测试环境,以及开发环境 2.那么每次在项目发布的时候,可能都需要改一下配置文件,修改一些路径才可以. 3.接下来讲一下spring boot的多环境配置,以及yml配置文件. 4.基于上一个demo项目.我们打开一下application.properties文件 5.可以看到里面是空的,什么都没有 6.我们修改一下端口号,添加 server.port=8088 然后我们启动访问一下,端口修改成功.

Spring Boot干货系列:(二)配置文件解析

Spring Boot:配置文件解析   前言 上一篇介绍了Spring Boot的入门,知道了Spring Boot使用"习惯优于配置"(项目中存在大量的配置,此外还内置了一个习惯性的配置,让你无需手动进行配置)的理念让你的项目快速运行起来.所以,我们要想把Spring Boot玩的溜,就要懂得如何开启各个功能模块的默认配置,这就需要了解Spring Boot的配置文件application.properties. 正文 Spring Boot使用了一个全局的配置文件applicat

【转】Spring Boot干货系列:(三)启动原理解析

前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面纱,让它不在神秘. 正文 我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication public class Application { public static void main(String[] args) { Spri

Spring Boot干货系列:(一)优雅的入门篇

Spring Boot干货系列:(一)优雅的入门篇http://www.cnblogs.com/zheting/p/6707032.html  全篇参考:http://www.cnblogs.com/zheting/category/966890.html 前言 Spring一直是很火的一个开源框架,在过去的一段时间里,Spring Boot在社区中热度一直很高,所以决定花时间来了解和学习,为自己做技术储备.   正文 首先声明,Spring Boot不是一门新技术,所以不用紧张.从本质上来说,

Spring Boot干货系列:(三)启动原理解析

Spring Boot干货系列:(三)启动原理解析 2017-03-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面纱,让它不在神秘. 正文 我们开发任何一个Spring Boot项目,都会用到如下的启动类 从上面代码可以看出,Annotation定义(@SpringBootApplicat

Spring Boot干货系列:(四)Thymeleaf篇

Spring Boot干货系列:(四)Thymeleaf篇 原创 2017-04-05 嘟嘟MD 嘟爷java超神学堂 前言 Web开发是我们平时开发中至关重要的,这里就来介绍一下Spring Boot对Web开发的支持. 正文 Spring Boot提供了spring-boot-starter-web为Web开发予以支持,spring-boot-starter-web为我们提供了嵌入的Tomcat以及Spring MVC的依赖. 项目结构推荐 一个好的项目结构会让你开发少一些问题,特别是Spr

Spring Boot学习记录(一)--环境搭建

Spring Boot学习记录(一)–环境搭建 标签(空格分隔): spring-boot 最近趁着下班闲时间学习spring-boot,记录下学习历程,最后打算实战一个API管理平台,下面开始环境配置. 1.工程结构 使用maven建立一个普通结构,因为spring-boot内嵌tomcat,所以打包只需要打包成jar就可以直接运行,所以并不像以前那样建立WEB程序了,目录如下,类可以先建立好放在那: 2.引入maven依赖 根据官方教程提示,直接引入parent就可以使用spring-boo