了解spring @Configuration 类

Posted

技术标签:

【中文标题】了解spring @Configuration 类【英文标题】:Understanding spring @Configuration class 【发布时间】: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?对代码本身有影响吗?

【问题讨论】:

【参考方案1】:

将 XML 迁移到 @Configuration

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

    创建一个@Configuration注解类:

    @Configuration
    public class MyApplicationContext 
    
    
    

    为每个&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
      
    
    

    为了导入beanFromSomewhereElse,我们需要导入它的定义。它可以在 XML 中定义,我们将使用 @ImportResource:

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

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

    @Import(OtherConfiguration.class)
    @Configuration
    public class MyApplicationContext 
      ...
    
    

    在我们导入其他 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);
    
    

    导入属性与从另一个 xml 或 @Configuration 类导入 bean 非常相似。我们将不使用@Qualifier,而是使用@Value,其属性如下:

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

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

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

    <context:annotation-config/>
    

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

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

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


使用这种方法的优缺点

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

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

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

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

底线:在您的应用程序上下文中组合 XML、@Configuration 和 annotations 非常好。 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(但这不是这个问题的重点)

以上是关于了解spring @Configuration 类的主要内容,如果未能解决你的问题,请参考以下文章

Spring Framework:可以在没有@Configuration的情况下创建相同@Component的两个bean吗?

Spring中的@Configuration注解你真的了解吗?

为啥 Spring Boot Application 类需要有 @Configuration 注解?

避免对 Spring Configuration 类进行类路径扫描

【Spring】简述@Configuration配置类注册BeanDefinition到Spring容器的过程

spring中@Configuration注解