理解 spring@Configuration 类

在问题 理解 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代替? 它对代码本身有什么影响吗?

69304 次浏览

将 XML 迁移到 @Configuration

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

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

    @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 beanFromSomewhereElse we 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 {
    ...
    }
    

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

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

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

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

    @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 @Configuration class. Instead of using @Qualifier we'll use @Value with properties as follows:

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

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

  6. 为了允许 spring 将这样的类视为 bean 容器,我们需要将这个标记放在上下文中,从而在 main 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. With XMLs you can define dependencies based on classes that are not available during compile time but are provided during run-time. With @Configuration classes you must have the classes available at compile time. Usually that's not an issue, but there are cases it may be.

一句话: 在应用程序上下文中组合 XML、 @Configuration注释非常好。Spring 不关心 bean 的声明方法。