Java 理解 spring @Configuration 类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24014919/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 09:44:50  来源:igfitidea点击:

Understanding spring @Configuration class

javaspringconfigurationautowired

提问by Avi

Following the question Understanding Spring @Autowired usageI wanted to create a complete knowledge base for the other option of spring wiring, the @Configurationclass.

在“理解 Spring @Autowired 用法”这个问题之后,我想为Spring接线的另一个选项创建一个完整的知识库,即@Configuration类。

Let's assume I have a spring XML file that looks like this:

假设我有一个如下所示的 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>

How can I use @Configurationinstead? Does it have any affect on the code itself?

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

采纳答案by Avi

Migrating XML to @Configuration

将 XML 迁移到 @Configuration

It is possible to migrate the xml to a @Configurationin a few steps:

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

  1. Create a @Configurationannotated class:

    @Configuration
    public class MyApplicationContext {
    
    }
    
  2. For each <bean>tag create a method annotated with @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. In order to import beanFromSomewhereElsewe need to import it's definition. It can be defined in an XML and the we'll use @ImportResource:

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

    If the bean is defined in another @Configurationclass we can use the @Importannotation:

    @Import(OtherConfiguration.class)
    @Configuration
    public class MyApplicationContext {
      ...
    }
    
  4. After we imported other XMLs or @Configurationclasses, we can use the beans they declare in our context by declaring a private member to the @Configurationclass as follows:

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

    Or use it directly as parameter in the method which defines the bean that depends on this beanFromSomewhereElseusing @Qualifieras follows:

    @Bean(name = "anotherBean")
    public AnotherClass getAnotherClass(@Qualifier (value = "beanFromSomewhereElse") final StrangeBean beanFromSomewhereElse) {
      return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse);
    }
    
  5. Importing properties is very similar to importing bean from another xml or @Configurationclass. Instead of using @Qualifierwe'll use @Valuewith properties as follows:

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

    This can be used with SpELexpressions as well.

  6. In order to allow spring to treat such classes as beans containers we need to mark this in our main xml by putting this tag in the context:

    <context:annotation-config/>
    

    You can now import @Configurationclasses exactly the same as you would create a simple bean:

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

    There are ways to avoid spring XMLs altogether but they are not in the scope of this answer. You can find out one of these options in my blog poston which I'm basing my answer.

  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我们将使用@Valuewith 属性代替 using ,如下所示:

    @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,但它们不在本答案的范围内。您可以在我的博客文章中找到这些选项之一,我的答案基于该文章



The advantages and disadvantages of using this method

使用这种方法的优缺点

Basically I find this method of declaring beans much more comfortable than using XMLs due to a few advantages I see:

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

  1. Typos- @Configurationclasses are compiled and typos just won't allow compilations
  2. Fail fast (compile time)- If you forget to inject a bean you'll fail on compile time and not on run-time as with XMLs
  3. Easier to navigate in IDE- between constructors of beans to understand the dependency tree.
  4. Possible to easily debug configuration startup
  1. 错别字-@Configuration类编译和错别字是不会允许编译
  2. 快速失败(编译时)- 如果您忘记注入 bean,您将在编译时失败,而不是像 XML 那样在运行时失败
  3. 更容易在 IDE 中导航- 在 bean 的构造函数之间了解依赖关系树。
  4. 可以轻松调试配置启动

The disadvantages are not many as I see them but there are a few which I could think of:

缺点在我看来并不多,但我能想到的有几个:

  1. Abuse- Code is easier to abuse than XMLs
  2. With XMLs you can define dependencies based on classes that are not available during compile time but are provided during run-time. With @Configurationclasses you must have the classes available at compile time. Usually that's not an issue, but there are cases it may be.
  1. 滥用- 代码比 XML 更容易被滥用
  2. 使用 XML,您可以根据在编译时不可用但在运行时提供的类来定义依赖项。对于@Configuration类,您必须在编译时提供可用的类。通常这不是问题,但在某些情况下可能会有问题。

Bottom line: It is perfectly fine to combine XMLs, @Configurationand annotationsin your application context. Spring doesn't care about the method a bean was declared with.

底线:在您的应用程序上下文中结合 XML@Configuration注释是非常好的。Spring 不关心声明 bean 的方法。