了解spring @Configuration类

Avi*_*Avi 106 java configuration spring autowired

了解了Spring @Autowired用法的问题之后,我想为另一个弹簧布线选项(@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>
Run Code Online (Sandbox Code Playgroud)

我该怎么用@Configuration呢?它对代码本身有什么影响吗?

Avi*_*Avi 148

将XML迁移到 @Configuration

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

  1. 创建带@Configuration注释的类:

    @Configuration
    public class MyApplicationContext {
    
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 对于每个<bean>标记,创建一个注释为的方法@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
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 为了导入,beanFromSomewhereElse我们需要导入它的定义.它可以在XML中定义,我们将使用@ImportResource:

    @ImportResource("another-application-context.xml")
    @Configuration
    public class MyApplicationContext {
      ...  
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

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

    @Autowired
    @Qualifier(value = "beanFromSomewhereElse")
    private final StrangeBean beanFromSomewhereElse;
    
    Run Code Online (Sandbox Code Playgroud)

    或者直接在方法中使用它作为参数,该方法beanFromSomewhereElse使用@Qualifier如下定义依赖于此的bean :

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

    @Autowired
    @Value("${some.interesting.property}")
    private final String someInterestingProperty;
    
    Run Code Online (Sandbox Code Playgroud)

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

  6. 为了允许spring将这些类视为bean容器,我们需要在主xml中将此标记放在上下文中:

    <context:annotation-config/>
    
    Run Code Online (Sandbox Code Playgroud)

    您现在可以导入@Configuration与创建简单bean完全相同的类:

    <bean class="some.package.MyApplicationContext"/>
    
    Run Code Online (Sandbox Code Playgroud)

    有一些方法可以完全避免使用Spring XML,但它们不在本答案的范围内.您可以在我的博客文章中找到其中一个选项,我的答案基于这些选项.


使用这种方法的优点和缺点

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

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

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

  1. 滥用 - 代码比XML更容易被滥用
  2. 使用XML,您可以基于在编译期间不可用但在运行时提供的类来定义依赖项.对于@Configuration类,您必须在编译时提供类.通常这不是问题,但有些情况可能会发生.

结论:在应用程序上下文中组合XML @Configuration注释是完美的.Spring并不关心声明bean的方法.

  • 这就是@Profile注释和"$ {env.value}"语法的用途.使用@Profile("someName"),您可以标记整个配置,以便仅在配置文件处于活动状态时使用.在application.properties(或.yml)文件中,您可以设置spring.profiles.active = someName,default ...要根据环境变量动态设置它,请使用$ {SOME_ENV_VAR}语法作为spring的值. active.profiles并设置环境变量.Spring现在推荐使用java配置 - http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-configuration-classes (6认同)
  • @JoseChavez - 这是一个很好的论据,我已经听过几次了.我试图进行一些统计研究,在这些研究中我找不到任何在其罐子/战争之外使用XML的应用程序或系统.它的实际意义在于你需要解压缩jar并更改XML(我找不到任何人这样做)或重建你的jar(这是我所谈过的每个人说他们到目前为止已经完成的) .因此,底线 - 因为它可能是一个相当大的争论,它在现实生活中通常并不重要. (5认同)
  • 一个可能的缺点是配置丢失.假设你有一个类在开发中模拟一些功能,那么你想在UAT环境中将它换成另一个类.使用XML,只需更改配置并允许应用程序运行/重启.使用这些新的类配置,必须重新编译类. (2认同)