了解spring @Configuration类


108

理解“ 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>

我该如何使用@Configuration呢?它对代码本身有影响吗?

Answers:


151

将XML迁移到 @Configuration

@Configuration只需几个步骤即可将xml迁移到:

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

    @Configuration
    public class MyApplicationContext {
    
    }
  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
      }
    }
  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使用@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/>

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

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

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


使用此方法的优缺点

基本上,由于一些优势,我发现这种声明bean的方法比使用XML更舒适。

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

正如我所看到的那样,缺点并不多,但我可以想到一些缺点:

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

底线:在您的应用程序上下文中结合XML @Configuration注释是完全可以的。Spring不在乎使用bean声明的方法。


2
可能的缺点之一是配置丢失。假设您有一个模拟开发中某些功能的类,然后要将其替换为UAT环境中的另一个类。使用XML,则只需更改配置并允许应用程序运行/重启即可。使用这些新的类配置,必须重新编译这些类。
何塞

5
@JoseChavez-这是一个很好的论据,我已经听过几次了。我试图进行一些统计研究,在其中我找不到在jars / wars之外使用XML的任何应用程序或系统。它的实际含义是您需要解压缩jar并更改XML(我找不到找到XML的人)或重建您的jar(这是我与之交谈的所有人到目前为止所做的事情) 。因此,底线-尽管可能是一个相当大的论点,但在现实生活中通常并不重要。
2014年

6
这就是@Profile批注以及“ $ {env.value}”语法的目的。使用@Profile(“ someName”),您可以标记整个配置,以仅在配置文件处于活动状态时使用。在您的application.properties(或.yml)文件中,您可以设置spring.profiles.active = someName,default ...要基于环境变量动态设置它,请使用$ {SOME_ENV_VAR}语法作为spring的值。 active.profiles并设置环境变量。Spring现在建议使用Java配置-docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…–
Jack Viers

除了将每个bean定义为配置文件中的方法之外,还有什么替代方法?
Asif Mushtaq

@AsifMushtaq-您可以使用自动扫描功能,每个具有@Component @Service或其他此类注释的类都将自动制成Bean(但这不是此问题的重点)
Avi
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.