Spring核心技术(十一)——基于Java的容器配置(一)
基本概念: @Bean
和@Configuration
Spring中新的基于Java的配置的核心就是支持@Configuration
注解的类以及@Bean
注解的方法。
@Bean
注解用来表示一个方法会实例化,配置,并初始化一个新的由Spring IoC容器所管理的对象。其作用等于XML配置中的<beans>
标签下的<bean>
子标签。开发者可以用@Bean
注解来和任何的Spring@Component
来联合使用,但是,最常见的情况下,@Bean
注解还是应用到注解了@Configuration
的类下面的。
注解了@Configuration
的类就表示这个类的首要目的是用来管理Bean的配置的。而且,@Configuration
注解的类允许inter-bean
之类的依赖在类中通过方法调用来引用。最简单的配置如下:
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
上面的配置将等价于如下的XML配置:
<beans>
<bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>
全
@Configuration
对比轻@Bean
模式
当@Bean
注解的方法声明到了没有配置@Configuration
的类中时,这些方法就会作为轻@Bean
模式来处理。举例来说,Bean方法如果声明到了@Component
注解的类,或者普通的类之中,就是轻@Bean
模式。
和使用@Configuration
不同,轻@Bean
方法不能够声明inter-bean
的依赖,通常一个@Bean
方法不应该调用另一个@Bean
。
只有在注解了@Configuration
的类中使用@Bean
方法才是全模式。这回防止很多@Bean
方法多次调用,并且消除一些细微的bug。这些bug在轻模式很难被跟踪。
@Bean
和@Configuration
注解将会在本文中详细讨论,首先我们需要了解各种通过基于Java的配置创建容器的方法。
实例化Spring容器
本节描述的是使用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();
}
上面这段代码让MyServiceImpl
,Dependency1
以及Dependency2
都可以使用Spring的依赖注入注解进行装载,比如@Autowired
。
通过register(Class<?>..)
来构建容器
AnnotationConfigApplicationContext
类除了通过类来初始化,也可以通过无惨构造函数来进行构造,之后通过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等效的配置中,配置如下:
<beans>
<context:component-scan base-package="com.acme"/>
</beans>
在上面的例子中,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实例被注册到容器之中。
对于Web应用的支持
WebApplicationContext
接口关于AnnotationConfigApplicationContext
的一个变化的版本就是AnnotationConfigWebApplicationContext
。这一实现可以在配置Spring的ContextLoaderListener
这个Servlet的listener或者Spring MVC的DispatcherServlet的时候使用。下面就是web.xml中配置Spring MVC程序的一个配置:
<web-app>
<!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<!-- Configuration locations must consist of one or more comma- or space-delimited
fully-qualified @Configuration classes. Fully-qualified packages may also be
specified for component-scanning -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.AppConfig</param-value>
</context-param>
<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Declare a Spring MVC DispatcherServlet as usual -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<!-- Again, config locations must consist of one or more comma- or space-delimited
and fully-qualified @Configuration classes -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.web.MvcConfig</param-value>
</init-param>
</servlet>
<!-- map all requests for /app/* to the dispatcher servlet -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
使用@Bean
注解
@Bean
注解是一个方法级别的注解,和XML中的<bean />
标签的功能一直。该注解支持<bean/>
的一些配置属性,比如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:
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
两种声明都可以在ApplicationContext
中声明一个名为transferService
的Bean,实例的类型为TransferServiceImpl
:
transferService -> com.acme.TransferServiceImpl
Bean依赖
由@Bean
注解的方法可以有任意数量的参数来描述其依赖。距离来说,如果TransferService
的其中一个依赖为AccountRepository
的话,我们可以通过方法参数来构造:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
解析的机制是和基于构造的依赖注入基本一致的,可以参考前文Spring的依赖及其注入了解相关内容。
接收生命周期回调
任何通过@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="")
来代替默认的行为。
当然,在上面的Foo
例子当中,也可以直接调用init()
方法:
@Configuration
public class AppConfig {
@Bean
public Foo foo() {
Foo foo = new Foo();
foo.init();
return foo;
}
// ...
}
当直接使用Java的配置的时候,开发者可以任意操作对象,而不仅仅是依赖于容器的声明周期
指定Bean的作用域
使用@Scope
注解
开发者也可以通过Java配置的方式来指定@Bean
的作用域,开发者可以使用所有的标准的作用域,关于作用域的信息,可以在Spring中Bean的作用域一文中了解。
默认的作用域是singleton
,但是开发者可以通过@Scope
注解来覆盖掉默认值:
@Configuration
public class MyConfiguration {
@Bean
@Scope("prototype")
public Encryptor encryptor() {
// ...
}
}
@Scope注解以及作用域代理
Sprnig针对那些作用域的依赖是通过代理来工作的。在XML中,可以通过使用<aop:scoped-proxy/>
标签来达到这个目的。通过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的别名,@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();
}
}
Spring核心技术(十一)——基于Java的容器配置(一)的更多相关文章
- Spring核心技术(十二)——基于Java的容器配置(二)
使用@Configuration注解 @Configuration注解是一个类级别的注解,表明该对象是用来指定Bean的定义的.@Configuration注解的类通过@Bean注解的方法来声明Bea ...
- IOC容器--1.12. 基于 Java 的容器配置
用Java的方式配置Spring ,不使用Spring的XML配置,全权交给Java来做 JavaConfig是Spring的一个子项目,在Sring 4 之后成为核心功能 这种纯Java的配置方式 ...
- Spring IOC之基于注解的容器配置
Spring配置中注解比XML更好吗?基于注解的配置的介绍提出的问题是否这种途径比XML更好.简单来说就是视情况而定. 长一点的答案是每一种方法都有自己的长处也不足,而且这个通常取决于开发者决定哪一种 ...
- [译]17-spring基于java代码的配置元数据
spring还支持基于java代码的配置元数据.不过这种方式不太常用,但是还有一些人使用.所以还是很有必要介绍一下. spring基于java代码的配置元数据,可以通过@Configuration注解 ...
- Spring IoC — 基于Java类的配置
普通的POJO只要标注@Configuration注解,就可以为Spring容器提供Bean定义的信息了,每个标注了@Bean的类方法都相当于提供一个Bean的定义信息. 基于Java类的配置方法和基 ...
- Spring @Bean注解 (基于java的容器注解)
基于java的容器注解,意思就是使用Java代码以及一些注解,就可以取代spring 的 xml配置文件. 1-@Configuration & @Bean的配合 @Configuration ...
- Spring IOC之基于JAVA的配置
基础内容:@Bean 和 @Configuration 在Spring中新的支持java配置的核心组件是 @Configuration注解的类和@Bean注解的方法. @Bean注解被用于表明一个方法 ...
- Spring学习(13)--- 基于Java类的配置Bean 之 @Configuration & @Bean注解
基于Java配置选项,可以编写大多数的Spring不用配置XML,但有几个基于Java的注释的帮助下解释.从Spring3.0开始支持使用java代码来代替XML来配置Spring,基于Java配置S ...
- Spring(八)之基于Java配置
基于 Java 的配置 到目前为止,你已经看到如何使用 XML 配置文件来配置 Spring bean.如果你熟悉使用 XML 配置,那么我会说,不需要再学习如何进行基于 Java 的配置是,因为你要 ...
随机推荐
- Log4j日志框架小记
人啊,总是在学习中发现不足,不足中学习,学习中成长. 今天来系统记录一下对于常用日志组件的理解.配置.使用. 仅供参考, 错误之处请各路好汉不吝笔墨批评指正. 转载请注明出处 Log4j日志框架是Ap ...
- pay-spring-boot 开箱即用的Java支付模块,整合支付宝支付、微信支付
关于 使用本模块,可轻松实现支付宝支付.微信支付对接,从而专注于业务,无需关心第三方逻辑. 模块完全独立,无支付宝.微信SDK依赖. 基于Spring Boot. 依赖Redis. 我能做什么 支付宝 ...
- 如何加快HTML页面加载速度
1. 页面减肥 a. 页面的肥瘦是影响加载速度最重要的因素. b. 删除不必要的空格.注释. c. 将inline的script和css移到外部文件. d. 可以使用HTML Tidy来给HTML减肥 ...
- 【javascript】操作给定的二叉树,将其变换为源二叉树的镜像。
操作给定的二叉树,将其变换为源二叉树的镜像. 输入描述: 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ 11 9 ...
- socket使用非阻塞connect
在使用tcp的connect调用时,默认是使用阻塞方式,当服务器当前不可用时,connect会等待(内部在重试?)直到超时时间到达,而这个超时时间是系统内核规定的,不能使用setSocketOpt来设 ...
- 我的CentOS6.5下及windows7下 安装composer与Yii2的过程
用yii2以来,安装composer老是不成功,所以一直在windows下的php里,用直接解压的方法运行yii2. 后来越来越多的场合,需要用composer,终于下决心,要在Linux下搞掂它! ...
- sqlserver数据库备份方法
须事先准备一个工具curl,把它放在c盘.然后,在数据库所在服务器安装7z.最后把这2个存储过程执行,在sqlserver的代理中新建作业,即可实现备份操作. --备份指定数据库到本地和远程指定位置( ...
- Install your Application into RaspberryPi2 and automatically start up
如何安装和卸载应用程序到RaspberryPi2? 如何配置应用程序在RaspberryPi2开机后自动启动? How to install your app into RaspberryPi2? H ...
- fluent_python2
字典和集合 泛映射类型, 继承自collections.abc, Mapping和MutableMapping 标准库里的所有映射类型都是利用 dict 来实现的,因此它们有个共同的限制,即只有可散列 ...
- java并发编程:Executor、Executors、ExecutorService
1.Executor和ExecutorService Executor:一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable comma ...