组装Java-based的配置

  • 使用@Import注解

跟在Spring XML文件里使用<import>元素加入模块化的配置相似,@Import注解同意你载入其它配置类中的@Bean定义:

@Configuration
public class ConfigA { @Bean
public A a() {
return new A();
} } @Configuration
@Import(ConfigA.class)
public class ConfigB { @Bean
public B b() {
return new B();
} }

如今,当实例化上下文时。你仅仅须要显式的指定ConfigB,而不须要既提供ConfigA.class,又提供ConfigB.class:

public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class); // now both beans A and B will be available...
A a = ctx.getBean(A.class);
B b = ctx.getBean(B.class);
}

这样的方式简化了容器的初始化。由于仅仅须要处理一个类,而不是让开发人员记住构造期间的大量@Configuration类。

  • 导入@Bean的依赖注入

上面的演示样例能够工作,但太简单。

在大多数实际的场景中。beans会依赖还有一个跨配置类的bean。当使用XML时。这不是问题。由于不涉及到编译,当中一个bean仅仅须要声明ref="someBean"。剩下的交给Spring在容器初始化期间处理即可。当然,当使用@Configuration类时,Java编译器对配置模式产生一些限制。对其它beans的引用必须是合法的java语法。

幸运的是。解决该问题是非常easy的。正如我们已经讨论的,@Bean能够有随意多个用来描写叙述bean依赖的參数。让我们探讨一个更现实的场景。在这里将使用一些彼此依赖的@Configuration类:

@Configuration
public class ServiceConfig { @Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
} } @Configuration
public class RepositoryConfig { @Bean
public AccountRepository accountRepository(DataSource dataSource) {
return new JdbcAccountRepository(dataSource);
} } @Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig { @Bean
public DataSource dataSource() {
// return new DataSource
} } public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// everything wires up across configuration classes...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}

这里有另外的方法能够达到相同的效果。

记住,@Configuration根本上仅仅是容器中的还有一个bean-这意味着它们能够像其它bean那样充分利用@Autowired注入元数据。

注: 确保以这样的方式注入的都是简单类型的。

@Configuration类在容器初始化时被处理的相当早。用这样的方式强制注入依赖可能导致无法预料地过早初始化问题。仅仅要有可能就採用上面演示样例中基于參数的注入方式。

@Configuration
public class ServiceConfig { @Autowired
private AccountRepository accountRepository; @Bean
public TransferService transferService() {
return new TransferServiceImpl(accountRepository);
} } @Configuration
public class RepositoryConfig { @Autowired
private DataSource dataSource; @Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataSource);
} } @Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig { @Bean
public DataSource dataSource() {
// return new DataSource
} } public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// everything wires up across configuration classes...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}

在上面的演示样例中,使用@Autowired工作的非常好,而且提供了想要的模块化。但要确切地指明自己主动注入的bean定义在哪声明依然有点模糊。比如。一个开发人员正在查看ServiceConfig,那你怎么准确地知道@Autowired AccountRepository bean在哪声明的?在代码中并不明白,只是有时候这样即可。

记着Spring Tool Suite能够提供渲染图的工具,这些图展示了Spring Bean之间是怎么连起来的-这可能是你须要的。同一时候。你的Java IDE能够轻松的找到全部声明和使用AccountRepository类型的bean,并为你高速展现返回该类型的@Bean方法位置。

假设你不能接受这样的模糊性,并希望在你的IDE中能够从一个@Configuration类导航到还有一个,那就考虑注入配置类本身:

@Configuration
public class ServiceConfig { @Autowired
private RepositoryConfig repositoryConfig; @Bean
public TransferService transferService() {
// navigate 'through' the config class to the @Bean method!
return new TransferServiceImpl(repositoryConfig.accountRepository());
} }

在上面的解决方式中,我们能够非常明白地知道AccountRepository定义的地方。

然而,ServiceConfig如今紧紧地跟RepositoryConfig耦合了。这就是权衡。

紧耦合在某种程度上能够通过使用基于接口或抽象类的@Configuration类来减轻。考虑以下内容:

@Configuration
public class ServiceConfig { @Autowired
private RepositoryConfig repositoryConfig; @Bean
public TransferService transferService() {
return new TransferServiceImpl(repositoryConfig.accountRepository());
}
} @Configuration
public interface RepositoryConfig { @Bean
AccountRepository accountRepository(); } @Configuration
public class DefaultRepositoryConfig implements RepositoryConfig { @Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(...);
} } @Configuration
@Import({ServiceConfig.class, DefaultRepositoryConfig.class}) // import the concrete config!
public class SystemTestConfig { @Bean
public DataSource dataSource() {
// return DataSource
} } public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}

如今,ServiceConfig跟详细的DefaultRepositoryConfig类是松耦合的关系。而且内嵌的IDE工具依然实用:它非常easy为开发人员获取RepositoryConfig实现的类型层次。採用这样的方式,导航@Configuration和它们的依赖就变得跟寻常处理基于接口的代码导航没差别了。

  • 有条件的包括@Configuration类或@Beans

基于随意的系统状态。有条件地禁用一个完整的@Configuration类,甚至单独的@Bean方法一般是非常实用的。

一个常见的演示样例是。当一个特定的profile在Spring Environment中启用时,使用@Profile注解激活beans。

@Profile注解实际上实现了一个非常灵活的注解:@Conditional。@Conditional注解意味着在注冊@Bean之前。必须先咨询指定的org.springframework.context.annotation.Condition实现。

Condition接口的实现者仅仅需简单地提供一个返回true或false的matches(…​)方法。比如,以下是@Profile注解採用的Condition实现:

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if (context.getEnvironment() != null) {
// Read the @Profile annotation attributes
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
for (Object value : attrs.get("value")) {
if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
return true;
}
}
return false;
}
}
return true;
}

详细參考@Conditional javadocs

  • 结合Java和XML配置

Spring @Configuration类支持目的不是想要100%的替换Spring XML。一些设施。比方Spring XML命名空间仍旧是配置容器的完美方式。

在XML非常方便或必须的情况下,你有个选择:採用”XML为中心”的方式实例化容器。比方ClassPathXmlApplicationContext,或使用AnnotationConfigApplicationContext以”Java为中心”的方式,并使用@ImportResource注解导入须要的XML。

  • 在以”XML为中心”的情况下使用@Configuration类

从XML启动Spring容器,以特设模式包括@Configuration类可能是个更可选的方式。比如,在一个已经存在的使用Spring XML的大型代码库中,遵循按需原则创建@Configuration。并从现有的XML文件里包括它们是非常easy的。以下你将找到在这样的”XML为中心”的解决方式中使用@Configuration类的可选项。

记着@Configuration类本质上仅仅是容器中的bean定义。在以下的演示样例中,我们创建了一个名称为AppConfig的@Configuration类,并将它作为<bean/>定义包括到system-test-config.xml中。

由于<context:annotation-config/>是开启的,容器将会识别@Configuration注解。并正确地处理AppConfig中声明的@Bean方法。

@Configuration
public class AppConfig { @Autowired
private DataSource dataSource; @Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataSource);
} @Bean
public TransferService transferService() {
return new TransferService(accountRepository());
} }

system-test-config.xml例如以下:

<beans>
<!-- enable processing of annotations such as @Autowired and @Configuration -->
<context:annotation-config/>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/> <bean class="com.acme.AppConfig"/> <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>

jdbc.properties例如以下:

jdbc.properties
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=

main方法例如以下:

public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");
TransferService transferService = ctx.getBean(TransferService.class);
// ...
}

注: 在上面的system-test-config.xml中,AppConfig<bean/>没有声明一个id元素。假设没有bean引用它。那就没有必要指定id元素,否则就要通过name从容器获取bean(name相应bean定义中声明的id)。

DataSource也一样-它仅仅是通过类型自己主动注入(autowired by type),所以并不须要显式的分配一个bean id。

由于@Configuration被@Component元注解了(被注解注解,非常拗口),所以被@Configuration注解的类自己主动成为组件扫描(component scanning)的候选者。相同使用上面的场景。我们能够又一次定义system-test-config.xml来充分利用组件扫描。注意在这个演示样例中。我们不须要明白声明<context:annotation-config/>,由于<context:component-scan/>启用了相同的功能。

system-test-config.xml例如以下:

<beans>
<!-- picks up and registers AppConfig as a bean definition -->
<context:component-scan base-package="com.acme"/>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/> <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
  • 在@Configuration”类为中心”的情况下使用@ImportResourcedaoru导入XML

在将@Configuration类作为配置容器的主要机制的应用中,仍旧存在对XML的需求。

在那些场景中,能够使用@ImportResource,并定义所需的XML。这样做能够实现以”Java为中心”的方式配置容器,并保留最低限度的XML。

@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
public class AppConfig { @Value("${jdbc.url}")
private String url; @Value("${jdbc.username}")
private String username; @Value("${jdbc.password}")
private String password; @Bean
public DataSource dataSource() {
return new DriverManagerDataSource(url, username, password);
} }

properties-config.xml例如以下:

<beans>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
</beans>

jdbc.properties例如以下:

jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=

main方法例如以下:

public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
TransferService transferService = ctx.getBean(TransferService.class);
// ...
}

Spring Java-based容器配置(二)的更多相关文章

  1. Spring核心技术(十二)——基于Java的容器配置(二)

    使用@Configuration注解 @Configuration注解是一个类级别的注解,表明该对象是用来指定Bean的定义的.@Configuration注解的类通过@Bean注解的方法来声明Bea ...

  2. IOC容器--1.12. 基于 Java 的容器配置

    用Java的方式配置Spring ,不使用Spring的XML配置,全权交给Java来做 JavaConfig是Spring的一个子项目,在Sring 4  之后成为核心功能 这种纯Java的配置方式 ...

  3. [转] Spring - Java Based Configuration

    PS: Spring boot注解,Configuration是生成一个config对象,@Bean指定对应的函数返回的是Bean对象,相当于XML定义,ConfigurationProperties ...

  4. Spring核心技术(十一)——基于Java的容器配置(一)

    基本概念: @Bean和@Configuration Spring中新的基于Java的配置的核心就是支持@Configuration注解的类以及@Bean注解的方法. @Bean注解用来表示一个方法会 ...

  5. Spring Boot Server容器配置

    参数配置容器 server.xx开头的是所有servlet容器通用的配置,server.tomcat.xx开头的是tomcat特有的参数,其它类似. 所有参数绑定配置类:org.springframe ...

  6. [转载]Spring Java Based Configuration

    @Configuration & @Bean Annotations Annotating a class with the @Configuration indicates that the ...

  7. 从零开始学 Java - Spring 集成 Memcached 缓存配置(二)

    Memcached 客户端选择 上一篇文章 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)中我们讲到这篇要谈客户端的选择,在 Java 中一般常用的有三个: Memc ...

  8. 【Java】Spring之基于注释的容器配置(四)

    注释是否比配置Spring的XML更好? 基于注释的配置的引入引发了这种方法是否比XML“更好”的问题.答案是每种方法都有其优点和缺点,通常,由开发人员决定哪种策略更适合他们.由于它们的定义方式,注释 ...

  9. 2015年12月10日 spring初级知识讲解(二)最小化Spring XML配置 注解

    序,随着Spring容器管理Bean数量增加,XML文件会越来越大,而且纯手工配置XML很繁琐,Spring和JAVA都提供了一些注解方式用以简化XML配置. 目录 一.自动装配(autowiring ...

随机推荐

  1. Android 多线程之HandlerThread 完全详解

    关联文章: Android 多线程之HandlerThread 完全详解 Android 多线程之IntentService 完全详解 android多线程-AsyncTask之工作原理深入解析(上) ...

  2. nagios监控mongodb

    nagios本身不提供监控mongodb的服务,需要安装插件 已经有大神写好的插件nagios_plugin-mongodb 地址https://github.com/mzupan/nagios-pl ...

  3. ibatis传入list对象

    在使用ibatis的时候经常需要传入list对象,sql语句如下. <select id="GET-PERSONS" parameterClass="java.ut ...

  4. Yii2系列教程三:Database And Gii

    上一篇文章我们理了一下Yii2的MVC,Forms和Layouts,这篇文章就直接按照约定来说说Yii2与数据库相关的一些事情,如果你觉得不够的话,不急,更具体的用法我会在后续的教程给出,并且这里也会 ...

  5. 【Git】Git hangs while unpacking objects (Windows)

    Git hangs while unpacking objects (Windows) 14 Oct 2014 I'm not sure if this is because we're behind ...

  6. Python 自用代码(拆分txt文件)

    现有一个28G的txt文件,里面每一行是一个分词过的专利全文文档,一共370多万行.我需要把它按每五万行为单位做成一个json文件,格式大致如下: [{"id":"100 ...

  7. 字符串去重(hashSet)

    public static String deleteRepeat(String strn){          String s=strn;        String[] array = s.sp ...

  8. 淘宝Diamond架构分析

    转载:http://blog.csdn.net/szwandcj/article/details/51165954 早期的应用都是单体的,配置修改后,只要通过预留的管理界面刷新reload即可.后来, ...

  9. 查看FC HBA卡信息的方法

    在配置磁盘阵列或虚拟磁带库时,往往会以FC接口与主机对接,那么就涉及FC HBA卡的查看,本文就这个问题进行了总结与整理. 一.Windows 系统 在Windows系统中,可以使用FC HBA卡厂家 ...

  10. 后缀数组suffix array

    倍增算法,时间复杂度O(nlogn) sa从小到大保存相对大小的下标 理解LSD,x数组,sa数组 char s[maxn]; int sa[maxn],t[maxn],t2[maxn],c[maxn ...