1.基本概念: @Bean和@Configuration
Spring中新的基于Java的配置的核心就是支持@Configuration注解的类以及@Bean注解的方法
。
@Bean注解用来表示一个方法会实例化,配置,并初始化一个新的由Spring IoC容器所管理的对象。其作用等于XML配置中的
。开发者可以用@Bean注解来和任何的Spring@Component来联合使用
,但是,最常见的情况下,@Bean注解还是应用到注解了@Configuration的类下面
的。
注解了@Configuration的类就表示这个类的首要目的是用来管理Bean的配置的
。而且,@Configuration注解的类允许inter-bean之类的依赖在类中通过方法调用来引用
。最简单的配置如下:
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
上面的配置将等价于如下的XML配置:
全@Configuration
对比轻@Bean
模式
当@Bean注解的方法声明到了没有配置@Configuration的类中时,这些方法就会作为轻@Bean模式来处理。举例来说,Bean方法如果声明到了@Component注解的类,或者普通的类之中,就是轻@Bean模式。
和使用@Configuration不同,轻@Bean方法不能够声明inter-bean的依赖
,通常一个@Bean方法不应该调用另一个@Bean。
只有在注解了@Configuration的类中使用@Bean方法才是全模式
。这会防止很多@Bean方法多次调用,并且消除一些细微的bug
。这些bug在轻模式很难被跟踪。
2.用 AnnotationConfigApplicationContext方式来初始化容器
本节描述的是使用Spring的AnnotationConfigApplicationContext。在Spring 3.0后,各式各样的ApplicationContext实现都可用了,不只是@Configuration注解的类,还有一些注解了@Component的组件类以及注解JSR-330元数据的类等。
当注解了@Configuration的类作为输入的时候,注解了@Configuration的类本身也会被注册为一个Bean,其中注解了@Bean的方法都会被注册为Bean
。
当注解了@Component的类或者JSR-330的类作为输入的时候,他们同样会被注册为Bean,而且可以通过DI来注入到其他的类里面去,比如通过@Autowired或者@Inject注解
。
简单构造
在Spring使用XML作为输入
的时候,实例的ApplicationContext是ClassPathXmlApplicationContext
,而通过@Configuration注解的类
,实例化的ApplicationContext是AnnotationConfigApplicationContext
。下面的代码可以完全去除XML的配置就使用了Spring容器。
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
如前面所述,AnnotationConfigApplicationContext不仅仅可以和注解了@Configuration的类配合,任何注解了@Component或者是JSR-330的类同样可以作为输入来构造Sprign容器
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
通过register(Class>..)来构建容器
nnotationConfigApplicationContext类除了通过类来初始化,也可以通过无惨构造函数来进行构造,之后通过register()方法来配置。这种方法在通过编程的方式来构建AnnotationConfigApplicationContext的过程很有用。
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class, OtherConfig.class);
ctx.register(AdditionalConfig.class);
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
-
使能组件扫描
使能组件扫描只需要在@Configuration注解的类上配置即可:
@Configuration
@ComponentScan(basePackages = "com.acme")
public class AppConfig {
...
}
等同于下面的xml配置
在上面的例子中,com.acme包中的内容会被扫描,来查找其中注解了@Component的类,这些类都会被注册为Spring的Bean实例。AnnotationConfigApplicationContext也可以通过scan(String ...)方法来通过函数调用的方式来进行扫描配置:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("com.acme");
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
}
@Congirufation注解的类和@Component注解的类都是扫描的候选者
。在上面的例子中,如果AppConfig类在com.acme包中(或者是其子包之中),AppConfig都会被scan方法扫描到,在refresh()方法调用后,其中的@Bean注解的方法都会作为Bean实例被注册到容器之中
- 用 AnnotationConfigWebApplicationContext支持web应用
WebApplicationContext接口关于AnnotationConfigApplicationContext的一个变化的版本就是AnnotationConfigWebApplicationContext
。这一实现可以在配置Spring的ContextLoaderListener这个Servlet的listener或者Spring MVC的DispatcherServlet的时候使用。下面就是web.xml中配置Spring MVC程序的一个配置:
contextClass
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
contextConfigLocation
com.acme.AppConfig
org.springframework.web.context.ContextLoaderListener
dispatcher
org.springframework.web.servlet.DispatcherServlet
contextClass
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
contextConfigLocation
com.acme.web.MvcConfig
dispatcher
/app/*
3.使用@Bean注解
@Bean注解是一个方法级别的注解
,和XML中的init-method,destroy-method,autowiring以及name
等。
@Bean注解可以在注解了@Configuration或者@Component的类中使用。
-
声明Bean
通过将方法注解@Bean即可声明实例为Bean。开发者通过这个方法将Bean注册到ApplicationContext,方法返回的类型就是Bean的类型。默认情况下,方法的名字就是Bean默认的名字,参考如下Bean的声明:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
上面的代码完全等价于一下XML:
Bean依赖
由@Bean注解的方法可以有任意数量的参数来描述其依赖
。距离来说,如果TransferService的其中一个依赖为AccountRepository的话,我们可以通过方法参数来构造:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
接收生命周期回调
任何通过@Bean注解了的方法返回的类,都支持常规的生命周期回调,并可以通过使用JSR-250中的@PostContruct以及@PreDestroy
注解。
基本的Spring生命周期也是同样支持的,如果Bean实现了InitializingBean,DisposableBean或者是Lifecycle接口
的话,这些方法都会被容器调用。
标准的*Aware接口比如说BeanFactoryAware
,BeanNameAware
,MessageSourceAware
,ApplicationContextAware
等接口也是支持的。
@Bean也支持指定任意的初始化以及销毁回调函数,跟Spring XML配置中的init-method和destroy-method属性是一致的:
public class Foo {
public void init() {
// initialization logic
}
}
public class Bar {
public void cleanup() {
// destruction logic
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public Foo foo() {
return new Foo();
}
@Bean(destroyMethod = "cleanup")
public Bar bar() {
return new Bar();
}
}
默认情况下,通过
Java配置的Bean都会有一个close或者shutdown方法来作为自动的销毁回调
。如果开发者声明了close方法或者是shutdown方法
,但是不希望由容器来调用的话,可以在注解中标记为@Bean(destroyMethod="")
来代替默认的行为。
指定Bean的作用域
1)使用@Scope注解
默认的作用域是singleton,但是开发者可以通过@Scope注解来覆盖掉默认值:
@Configuration
public class MyConfiguration {
@Bean
@Scope("prototype")
public Encryptor encryptor() {
// ...
}
}
2)@Scope注解以及作用域代理
Sprnig针对那些作用域的依赖是通过代理来工作的
。在XML中,可以通过使用
标签来达到这个目的。通过Java配置的的@Scope注解也提供等价的支持
,默认的没有代理配置为ScopedProxyMode.NO
,也可以指定为ScopedProxyMode.TARGET_CLASS
或者ScopedProxyMode.INTERFACES
Java配置如下:
/ an HTTP Session-scoped bean exposed as a proxy
@Bean
@SessionScope
public UserPreferences userPreferences() {
return new UserPreferences();
}
@Bean
public Service userService() {
UserService service = new SimpleUserService();
// a reference to the proxied userPreferences bean
service.setUserPreferences(userPreferences());
return service;
}
-
自定义Bean的名字
默认情况下,配置类会读取@Bean方法中的方法的名字值作为Bean的名字。当然可以通过name属性来覆盖这个功能。
@Configuration
public class AppConfig {
@Bean(name = "myFoo")
public Foo foo() {
return new Foo();
}
}
-
Bean的别名
有时候会给一个Bean多个名字,作为Bean的别名,@Bean注解的name属性也支持Spring数组类型的值:
@Configuration
public class AppConfig {
@Bean(name = { "dataSource", "subsystemA-dataSource", "subsystemB-dataSource" })
public DataSource dataSource() {
// instantiate, configure and return DataSource bean...
}
}
-
Bean的描述
有的时候为Bean提供额外的文本描述可以让别人更了解该Bean的作用。这一点尤其在监视容器中的Bean的时候很有效。
可以通过使用@Description注解来做到:
@Configuration
public class AppConfig {
@Bean
@Description("Provides a basic example of a bean")
public Foo foo() {
return new Foo();
}
}
接下来另外一篇文章着重讲解@Configuration