从Spring 应用上下文获取 Bean 的常用姿势

1. 前言

通常,在Spring应用程序中,当我们使用 @Bean@Service@Controller@Configuration 或者其它特定的注解将 Bean 注入 Spring IoC 。然后我们可以使用 Spring 框架提供的 @Autowired 或者 JSR250JSR330 规范注解来使用由 Spring IoC 管理的 Bean

2. 从应用程序上下文中获取 Bean

今天我们将来学习如何从 ApplicationContext 中获取 Bean 。因为有些情况下我们不得不从应用程序上下文中来获取 Bean

2.1 获取所有的 Bean

ApplicationContext 提供了获取所有已经成功注入 Spring IoC 容器的 Bean 名称的方法 getBeanDefinitionNames() 。然后我们可以借助于其 getBean(String name) 方法使用 Bean 名称获取特定的 Bean。 我们使用之前文章中介绍的 CommandLineRunner 接口来打印一下结果。

 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.CommandLineRunner;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.ApplicationContext;
 
 import java.util.stream.Stream;
 
 /**
  * @author Felordcn
  */
 @SpringBootApplication
 public class WarSpringBootApplication implements CommandLineRunner {
     @Autowired
     private ApplicationContext applicationContext;
 
     public static void main(String[] args) {
         SpringApplication.run(WarSpringBootApplication.class, args);
 
 
     }
 
     @Override
     public void run(String... args) throws Exception {
         String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
 
         Stream.of(beanDefinitionNames).forEach(beanName->{
             System.out.println("beanName : " + beanName);
 
             Object bean = applicationContext.getBean(beanName);
 
             System.out.println("Spring bean : " + bean);
         });
 
     }
 }

运行应用会输出:

 2019-11-05 22:15:54.392  INFO 6356 --- [           main] cn.felord.war.WarSpringBootApplication   : Started WarSpringBootApplication in 4.663 seconds (JVM running for 7.58)
 beanName : org.springframework.context.annotation.internalConfigurationAnnotationProcessor
 Spring bean : org.springframework.context.annotation.ConfigurationClassPostProcessor@6c44052e
 beanName : org.springframework.context.annotation.internalAutowiredAnnotationProcessor
 Spring bean : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@5c371e13
 beanName : org.springframework.context.annotation.internalCommonAnnotationProcessor
 Spring bean : org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@530a8454
 beanName : org.springframework.context.event.internalEventListenerProcessor
 Spring bean : org.springframework.context.event.EventListenerMethodProcessor@1e34c607
 beanName : org.springframework.context.event.internalEventListenerFactory
 Spring bean : org.springframework.context.event.DefaultEventListenerFactory@5215cd9a
 beanName : fooController
 Spring bean : cn.felord.war.controller.FooController@31198ceb
 beanName : IServiceImpl
 Spring bean : cn.felord.war.controller.IServiceImpl@51671b08
  <more...>

2.2 通过名称获取特定的 Bean

从上面打印的信息我们也能看出来一些端倪。

  • 有的 beanName 是类全限定名。
  • @Component@Repository@Service@Controller等注解创建 Bean 时,如果不指定bean名称,名称的默认规则是类名的首字母小写,如 cn.felord.war.controller.FooControllerfooController。如果类名前两个或以上个字母都是大写,那么名称与类名一样,如 cn.felord.war.controller.IServiceImplIServiceImpl
  • @Bean 标识的 Bean 默认 为方法名称。
  • 配置类相关注解 @Configuration 一般使用类全限定名。

但是请注意:如果你在声明 Bean 的时候指定了名称就只是你指定的名称 。如果我们熟悉这些规则,使用上面提到的getBean(String name) 方法不失为一种好办法。

2.3 通过类型来获取 Bean

如果我们不清楚我们想要的特定类型 Bean 的名称,我们可以根据类型来获取 BeanApplicationContext 提供了可以加载特定类型的 Bean 的所有 Bean 的方法getBeansOfType()。它将返回 Map <String,Object> 其中键是 Bean 名称,而值是 Bean 的实际对象。

我们修改 2.1 章节 例子中的 run 方法:

     @Override
     public void run(String... args) throws Exception {
         Map<String, FooController> beansOfType = applicationContext.getBeansOfType(FooController.class);
 
 
         beansOfType.forEach((beanName,bean)->{
             System.out.println("beanName : " + beanName);
             System.out.println("bean : " + bean);
         });
     }

再次运行,控制台打印出:

 beanName : fooController
 bean : cn.felord.war.controller.FooController@545f80bf

2.4 获取特定 Bean 声明注解标记的 Bean

ApplicationContextgetBeansWithAnnotation() 方法可以让我们获取 @Service@Controller或任何其它可以用来创建 Bean 的注解创建的 Bean

     @Override
     public void run(String... args) throws Exception {
         Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(Controller.class);
 
         beansWithAnnotation.forEach((beanName,bean)->{
             System.out.println("beanName : " + beanName);
             System.out.println("bean : " + bean);
         });
     }

打印出:

 beanName : fooController
 bean : cn.felord.war.controller.FooController@18ca3c62
 beanName : basicErrorController
 bean : org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController@2c0f7678

3. 总结

在本文中,我们学习如何从 Spring 应用上下文中获取所有 Bean 的列表。有时我们需要检查我们期望的 Bean 是否在 Spring 上下文中加载,或者我们需要检查 Spring IoC 声明的特定的 Bean 。当然你可以开启Spring Boot Actuatorbeans 端点来获取所有的 Bean 信息。

关注公众号:码农小胖哥,获取更多资讯

个人博客:https://felord.cn

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容