了解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
为每个<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
为了导入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 类进行类路径扫描