【问题标题】:Understanding spring @Configuration class了解spring @Configuration 类
【发布时间】:2014-07-23 18:34:55
【问题描述】:

根据Understanding Spring @Autowired usage 的问题,我想为弹簧接线的另一个选项@Configuration 类创建一个完整的知识库。

假设我有一个如下所示的 Spring XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  <import resource="another-application-context.xml"/>

  <bean id="someBean" class="stack.overflow.spring.configuration.SomeClassImpl">
    <constructor-arg value="${some.interesting.property}" />
  </bean>

  <bean id="anotherBean" class="stack.overflow.spring.configuration.AnotherClassImpl">
    <constructor-arg ref="someBean"/>
    <constructor-arg ref="beanFromSomewhereElse"/>
  </bean>
</beans>

如何改用@Configuration?对代码本身有影响吗?

【问题讨论】:

    标签: java spring configuration autowired


    【解决方案1】:

    将 XML 迁移到 @Configuration

    可以通过几个步骤将 xml 迁移到 @Configuration

    1. 创建一个@Configuration注解类:

      @Configuration
      public class MyApplicationContext {
      
      }
      
    2. 为每个&lt;bean&gt; 标签创建一个带有@Bean 注释的方法:

      @Configuration
      public class MyApplicationContext {
      
        @Bean(name = "someBean")
        public SomeClass getSomeClass() {
          return new SomeClassImpl(someInterestingProperty); // We still need to inject someInterestingProperty
        }
      
        @Bean(name = "anotherBean")
        public AnotherClass getAnotherClass() {
          return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse); // We still need to inject beanFromSomewhereElse
        }
      }
      
    3. 为了导入beanFromSomewhereElse,我们需要导入它的定义。它可以在 XML 中定义,我们将使用 @ImportResource:

      @ImportResource("another-application-context.xml")
      @Configuration
      public class MyApplicationContext {
        ...  
      }
      

      如果 bean 是在另一个 @Configuration 类中定义的,我们可以使用 @Import 注释:

      @Import(OtherConfiguration.class)
      @Configuration
      public class MyApplicationContext {
        ...
      }
      
    4. 在我们导入其他 XML 或 @Configuration 类之后,我们可以通过向 @Configuration 类声明一个私有成员来使用它们在我们的上下文中声明的 bean,如下所示:

      @Autowired
      @Qualifier(value = "beanFromSomewhereElse")
      private final StrangeBean beanFromSomewhereElse;
      

      或者在定义依赖这个beanFromSomewhereElse的bean的方法中直接作为参数使用@Qualifier如下:

      @Bean(name = "anotherBean")
      public AnotherClass getAnotherClass(@Qualifier (value = "beanFromSomewhereElse") final StrangeBean beanFromSomewhereElse) {
        return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse);
      }
      
    5. 导入属性与从另一个 xml 或 @Configuration 类导入 bean 非常相似。我们将不使用@Qualifier,而是使用@Value,其属性如下:

      @Autowired
      @Value("${some.interesting.property}")
      private final String someInterestingProperty;
      

      这也可以与 SpEL 表达式一起使用。

    6. 为了让 spring 将这些类视为 bean 容器,我们需要在我们的主 xml 中通过将这个标签放在上下文中来标记它:

      <context:annotation-config/>
      

      您现在可以像创建简单 bean 一样导入 @Configuration 类:

      <bean class="some.package.MyApplicationContext"/>
      

      有一些方法可以完全避免使用 Spring XML,但它们不在此答案的范围内。您可以在我的 blog post 中找到这些选项之一,我的答案正是基于此。


    使用这种方法的优缺点

    基本上,我发现这种声明 bean 的方法比使用 XML 更舒适,因为我看到了一些优点:

    1. 错别字 - @Configuration 类已编译,错别字不允许编译
    2. 快速失败(编译时) - 如果您忘记注入 bean,您将在编译时失败,而不是像 XML 那样在运行时失败
    3. 在 IDE 中更易于导航 - 在 bean 的构造函数之间了解依赖关系树。
    4. 可以轻松调试配置启动

    我看到的缺点并不多,但我能想到一些:

    1. 滥用 - 代码比 XML 更容易被滥用
    2. 使用 XML,您可以基于在编译时不可用但在运行时提供的类定义依赖关系。对于@Configuration 类,您必须在编译时拥有可用的类。通常这不是问题,但在某些情况下可能会出现问题。

    底线:在您的应用程序上下文中组合 XML、@Configurationannotations 非常好。 Spring 不关心声明 bean 的方法。

    【讨论】:

    • 一个可能的缺点是配置丢失。假设您有一个模拟开发中某些功能的类,然后您想将它换成 UAT 环境中的另一个类。使用 XML,只需更改配置并允许应用程序运行/重新启动。使用这些新的类配置,必须重新编译这些类。
    • @JoseChavez - 这是一个很好的论点,我已经听过几次了。我试图做一些统计研究,在其中我找不到任何在其 jars/wars 之外使用 XML 的应用程序或系统。它的实际含义是您需要解压缩 jar 并更改 XML(我找不到这样做的任何人)或重建您的 jar(这是我与之交谈的每个人都说他们到目前为止所做的) .所以,底线 - 因为这可能是一个相当大的论点,它在现实生活中通常并不重要。
    • 这就是@Profile 注释和“${env.value}”语法的用途。使用 @Profile("someName") 您可以标记整个配置,以便仅在配置文件处于活动状态时使用。在您的 application.properties(或 .yml)文件中,您可以设置 spring.profiles.active=someName,default... 要根据环境变量动态设置它,请使用 ${SOME_ENV_VAR} 语法作为 spring 的值。 active.profiles 并设置环境变量。 Spring 现在推荐使用 java config - docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
    • 除了将每个 bean 定义为配置文件中的方法之外,还有什么替代方法?
    • @AsifMushtaq - 您可以使用自动扫描功能,每个具有 @Component @Service 或其他此类注释的类将自动制成一个 bean(但这不是这个问题的重点)
    猜你喜欢
    • 2011-02-20
    • 1970-01-01
    • 2014-12-14
    • 1970-01-01
    • 2017-01-07
    • 1970-01-01
    • 2019-11-24
    • 2017-02-08
    • 2011-12-31
    相关资源
    最近更新 更多