专栏首页码农小胖哥的码农生涯从Spring 应用上下文获取 Bean 的常用姿势

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

1. 前言

通常,在Spring应用程序中,当我们使用 @Bean@Service@Controller@Configuration 或者其它特定的注解将 Bean 注入 Spring IoC 。然后我们可以使用 Spring 框架提供的 @Autowired 或者 JSR250、JSR330 规范注解来使用由 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 的名称,我们可以根据类型来获取 Bean 。ApplicationContext 提供了可以加载特定类型的 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 Actuator 的 beans 端点来获取所有的 Bean 信息。

本文分享自微信公众号 - 码农小胖哥(Felordcn),作者:码农小胖哥

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 微服务发现组件与配置管理组件NACOS环境快速体验

    Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您实现动态服务发现、服务配置管理、服务及流量管理。Nacos 帮助...

    码农小胖哥
  • 快速学会Springboot中编写Mock单元测试

    软件测试是一个应用软件质量的保证。java开发者开发接口往往忽视接口单元测试。作为java开发如果会Mock单元测试,那么你的bug量将会大大降低。spring...

    码农小胖哥
  • Java Web 面试中关于Spring MVC的必问题,不收藏血亏!

    Spring MVC 实现了一些明确而且相对低耦合的概念,可以让开发者很容易开发和测试他们的Web应用。这些概念有:

    码农小胖哥
  • Spring的原理性总结

    Bean的生命过程可以借鉴Servlet的生命过程,了解其生命过程对于不管是思想还是以后的使用都很有帮助;

    小勇DW3
  • Spring官网阅读(八)容器的扩展点(三)(BeanPostProcessor)

    *从上面的执行结果我们可以得出一个结论,BeanPostProcessor接口中的两个方法的执行时机在属性注入之后。*因为从打印的结果我们可以发现,IndexS...

    程序员DMZ
  • 凉凉了,Eureka 宣布闭源,Spring Cloud 何去何从?

    今年 Dubbo 活了,并且被 Apache 收了。同时很不幸,Spring Cloud 下的 Netflix Eureka 组件项目居然宣布停更了。。

    Java技术栈
  • Spring Cloud Eureka 自我保护机制实战分析

    之前栈长在Java技术栈微信公众号分享过 Spring Cloud Eureka 的系列文章:

    Java技术栈
  • Spring官网阅读系列(八):容器的扩展点(BeanPostProcessor)

    从上面的执行结果我们可以得出一个结论,BeanPostProcessor接口中的两个方法的执行时机在属性注入之后。因为从打印的结果我们可以发现,IndexSer...

    秃顶的Java程序员
  • 剑指offer第8题:青蛙跳台阶

    根据题意,我们可以看出整个题目的思路是十分清晰的。我们需要想办法将题目语言,先转化为数学符号,最后再转化为编程语言就十分方便了。下面我们来分析一些这道题目。

    鹏-程-万-里
  • [Java面试五]Spring总结以及在面试中的一些问题.

    一枝花算不算浪漫

扫码关注云+社区

领取腾讯云代金券