spring核心技术(1)
#spring核心技术
## 基本原理-容器和bean
1、在Spring中,那些组成你应用程序的主体(backbone)及由Spring IoC容器所管理的对象,被称之为bean。 简单地讲,bean就是由Spring容器初始化、装配及管理的对象。
2、org.springframework.beans.factory.BeanFactory 是Spring IoC容器的实际代表者,IoC容器负责容纳此前所描述的bean,并对bean进行管理。
3、在Spring中,BeanFactory是IoC容器的核心接口。 它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
4、ApplicationContext在WEB应用中的实例化
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
ContextLoaderListener首先检查contextConfigLocation参数,如果它不存在,它将使用/WEB-INF/applicationContext.xml作为默认值。如果已存在,它将使用分隔符(逗号、冒号或空格)将字符串分解成应用上下文件位置路径。
5、实例化容器
ApplicationContext context = new ClassPathXmlApplicationContext( new String[] {"services.xml", "daos.xml"});
## 依赖
1、依赖注入(DI)背后的基本原理是对象之间的依赖关系(即一起工作的其它对象)只会通过以下几种方式来实现:Setter注入和构造器注入。因此,容器的工作就是创建bean时注入那些依赖关系。
2、循环依赖
(1)构造器的循环依赖
(2)field属性的循环依赖
构造器的循环依赖问题无法解决,只能拋出BeanCurrentlyInCreationException异常,在解决属性循环依赖时,spring采用的是提前暴露对象的方法。
Spring的循环依赖的理论依据基于Java的引用传递,当获得对象的引用时,对象的属性是可以延后设置的(但是构造器必须是在获取引用之前)。
3、static工厂方法返回对象实例
<bean id="exampleBean" class="examples.ExampleBean" factory-method="createInstance"> <constructor-arg ref="anotherExampleBean"/> <constructor-arg value="1"/> </bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/>
public class ExampleBean { // a private constructor private ExampleBean(...) { ... } public static ExampleBean createInstance ( AnotherBean anotherBean, int i) { ExampleBean eb = new ExampleBean (...); // some other operations... return eb; } }
请注意,传给static工厂方法的参数由constructor-arg元素提供,这与使用构造器注入时完全一样。
## bean的作用域
singleton:在每个Spring IoC容器中一个bean定义对应一个对象实例。
prototype:一个bean定义对应多个对象实例。
request:在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例, 它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。
session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
global session:在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。
1、根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。
2、request、session以及global session 仅在基于web的应用中使用,如果你用Spring Web MVC,即用SpringDispatcherServlet或DispatcherPortlet来处理请求,则不需要做特别的配置:DispatcherServlet 和 DispatcherPortlet已经处理了所有有关的状态,否则需要在Web应用的'web.xml'文件中增加 javax.servlet.ServletRequestListener 定义
<listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
## 定制bean特性
### 生命周期回调
1、Spring提供了几个标志接口(marker interface),这些接口用来改变容器中bean的行为;它们包括InitializingBean
和DisposableBean。实现这两个接口的bean在初始化和析构时容器会调用前者的afterPropertiesSet()方法,
以及后者的destroy()方法。
2、Spring在内部使用BeanPostProcessor实现来处理它能找到的任何标志接口并调用相应的方法。
如果你需要自定义特性或者生命周期行为,你可以实现自己的 BeanPostProcessor。
### 初始化回调
1、实现org.springframework.beans.factory.InitializingBean接口允许容器在设置好bean的所有必要属性后,执行初始化事宜。
InitializingBean接口仅指定了一个方法
void afterPropertiesSet() throws Exception;
2、通常,要避免使用InitializingBean接口并且不鼓励使用该接口,因为这样会将代码和Spring耦合起来。
有一个可选的方案是,可以在Bean定义中指定一个普通的初始化方法,然后在XML配置文件中通过指定
init-method属性来完成。
如下面的定义所示:
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean { public void init() { // do some initialization work } }
### 析构回调
1、实现org.springframework.beans.factory.DisposableBean接口的bean允许在容器销毁该bean的时候获得
一次回调。DisposableBean接口也只规定了一个方法:
void destroy() throws Exception;
2、通常,要避免使用DisposableBean标志接口而且不鼓励使用该接口,因为这样会将代码与Spring耦合在一
起。有一个可选的方案是,在bean定义中指定一个普通的析构方法,然后在XML配置文件中通过指定
destroy-method属性来完成。如下面的定义所示:
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean { public void cleanup() { // do some destruction work (like releasing pooled connections) } }
3、在Spring中有三种方式可以控制bean的生命周期行为: InitializingBean 和 DisposableBean 回调接口;
自定义init() 和 destroy() 方法; @PostConstruct 和@PreDestroy annotations.
4、在非web应用中优雅地关闭Spring IoC容器
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext(new String []{"beans.xml"}); // add a shutdown hook for the above context... ctx.registerShutdownHook();