组装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. ajaxfileupload-上传文件示例

    1.引用文件 ajaxfileupload.js @{ ViewBag.Title = "数据导入"; Layout = "~/Views/Shared/_IndexLa ...

  2. java--模板方法模式

    /* 需求:获取一段程序的运行时间 原理:获取程序开始和结束的时间并相减即可 获取时间:用java中已有的一个类:System.currentTimeMillis(); 当代码完成优化后,就可以解决这 ...

  3. 学习Microsoft SQL Server 2008技术内幕:T-SQL语法基础--第4章

    第4章 子查询 4.2.1 Exist 谓语: use TSQLFundamentals2008 select * from Sales.Customers as C where c.country= ...

  4. 协同过滤中的Grey Sheep问题

    寒神解释:某些用户的倾向性和品味没有一致性,比较散.因此在协同过滤这种算法里,没办法和某个group有很高的相似/一致度,推荐会失效. 我理解是寻找邻居时候计算得到的相似度和其他用户相似度都非常小,或 ...

  5. EF 通用数据层父类方法小结

    MSSql 数据库 数据层 父类 增删改查: using System;using System.Collections.Generic;using System.Data;using System. ...

  6. 下载谷歌浏览器(Chrome)扩展离线安装包crx文件最简单的方法

    转:http://alyzq.com/?p=627 如果不会使用,请看下面的操作步骤 引言(可以不看): 下面介绍一下,下载谷歌浏览器(Google Chrome)扩展的离线安装包crx文件最简单的方 ...

  7. 【spring】spring boot中使用@EnableTransactionManagement 以后,spring mvc接收前台ajax的post方法传过来的参数,使用@RequestBody接收不到参数

    在启动类上添加了注解: @EnableTransactionManagement, postMan测试接口,以这种方式传递参数: 测试结果: 接收不到参数 问题解决: 原因:是因为 这个项目中的Con ...

  8. C#的Xamarin开发小米盒子应用并以WCF实现微信通知

    对于熟悉C#语言的开发人员而言,用Xamarin开发Android应用也是一个不错的选择.小米盒子是Android系统.当然也就能够使用Xamarin来开发.首选来看效果图. watermark/2/ ...

  9. $apply用法注意

    Angular为我们提供了一些接口绑定JavaScript代码和数据,而绑定数据改变和更新angular则是使用$apply方法实现的. $apply 进行数据变化检查的实际上是$digest函数,但 ...

  10. Linux设备驱动之mmap设备操作

    1.mmap系统调用 void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset); 功能:负责把文件内容 ...