美文网首页
从Spring 应用上下文获取 Bean 的常用姿势

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

作者: 码农小胖哥 | 来源:发表于2019-11-05 23:53 被阅读0次

    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

    相关文章

      网友评论

          本文标题:从Spring 应用上下文获取 Bean 的常用姿势

          本文链接:https://www.haomeiwen.com/subject/pidybctx.html