在 applicationContext.xml 中配置完 bean 之后, Bean 的声明周期状态有哪些。生命周期的各个阶段可以做什么。在 applicationContext.xml 配置 bean 的作用域有哪些。其中各个作用域代表的是什么。适用于什么情况。这篇文章做一个记录。
可以直接查看图片,图片来自 Spring Bean Life Cycle
从上图看出, Bean 初始化完成包括9个步骤。其中一些步骤包括接口的实现,其中包括 BeanNameAware 接口, BeanFactoryAware 接口。 ApplicationContextAware 接口。 BeanPostProcessor 接口, InitializingBean 接口。那么这些接口在整个生命周期阶段都起到什么作用?后面我们一一介绍。
当 Bean 全部属性设置完毕后,往往需要执行一些特定的行为, Spring 提供了两种方式来实现此功能:
init-mothod 方法 initializingBean 接口 如下:
package com.model;
public classInitBean{
public static final String NAME = "mark";
public static final int AGE = 20;
publicInitBean(){
// TODO Auto-generated constructor stub
System.out.println("执行构造方法");
}
public String name;
public int age ;
publicStringgetName(){
return name;
}
publicvoidsetName(String name){
this.name = name;
}
publicintgetAge(){
return age;
}
publicvoidsetAge(intage){
this.age = age;
}
publicvoidinit(){
System.out.println("调用init方法进行成员变量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
}
编写加载器
package com.model;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.service.UserServiceImpl;
public classMain{
publicstaticvoidmain(String[] args){
ApplicationContext context = new ClassPathXmlApplicationContext("initbean.xml");
InitBean bean = (InitBean) context.getBean("init");
}
}
配置 Bean
注意 init-method 参数
<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<beanid="init"class="com.model.InitBean"init-method="init"/>
</beans>
执行结果
实现 InitializingBean 接口
实现 InitializingBean 接口会实现 afterPropertiesSet 方法,这个方法会自动调用。但是这个方式是侵入性的。一般情况下,不建议使用。
实现 afterPropertiesSet 方法
package com.model;
import org.springframework.beans.factory.InitializingBean;
public classInitBeanimplementsInitializingBean{
public static final String NAME = "mark";
public static final int AGE = 20;
publicInitBean(){
// TODO Auto-generated constructor stub
System.out.println("执行构造方法");
}
public String name;
public int age ;
publicStringgetName(){
return name;
}
publicvoidsetName(String name){
this.name = name;
}
publicintgetAge(){
return age;
}
publicvoidsetAge(intage){
this.age = age;
}
publicvoidinit(){
System.out.println("调用init方法进行成员变量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
@Override
publicvoidafterPropertiesSet()throwsException{
// TODO Auto-generated method stub
System.out.println("调用init方法进行成员变量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
}
配置 xml
<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- <bean id="init" class="com.model.InitBean" init-method="init"/> -->
<beanid="init"class="com.model.InitBean"init-method="init"/>
</beans>
结果:
同样,上图中表示来 Bean 销毁时候的过程。包括 DisposableBean 接口。
使用 destroy-method 方法
package com.model;
import org.springframework.beans.factory.InitializingBean;
public classInitBeanimplementsInitializingBean{
public static final String NAME = "mark";
public static final int AGE = 20;
publicInitBean(){
// TODO Auto-generated constructor stub
System.out.println("执行构造方法");
}
public String name;
public int age ;
publicStringgetName(){
return name;
}
publicvoidsetName(String name){
this.name = name;
}
publicintgetAge(){
return age;
}
publicvoidsetAge(intage){
this.age = age;
}
publicvoidinit(){
System.out.println("调用init方法进行成员变量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
@Override
publicvoidafterPropertiesSet()throwsException{
// TODO Auto-generated method stub
System.out.println("调用init方法进行成员变量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
publicvoidclose(){
System.out.println("bean被销毁");
}
}
配置 Bean
<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- <bean id="init" class="com.model.InitBean" init-method="init"/> -->
<beanid="init"class="com.model.InitBean"destroy-method="close"/>
</beans>
配置加载器
package com.model;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.service.UserServiceImpl;
public classMain{
publicstaticvoidmain(String[] args){
AbstractApplicationContext context = new ClassPathXmlApplicationContext("initbean.xml");
context.registerShutdownHook();
InitBean bean = (InitBean) context.getBean("init");
}
}
结果:
实现 DisposableBean 接口
实现 DisposableBean 接口
package com.model;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public classInitBeanimplementsInitializingBean,DisposableBean{
public static final String NAME = "mark";
public static final int AGE = 20;
publicInitBean(){
// TODO Auto-generated constructor stub
System.out.println("执行构造方法");
}
public String name;
public int age ;
publicStringgetName(){
return name;
}
publicvoidsetName(String name){
this.name = name;
}
publicintgetAge(){
return age;
}
publicvoidsetAge(intage){
this.age = age;
}
publicvoidinit(){
System.out.println("调用init方法进行成员变量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
@Override
publicvoidafterPropertiesSet()throwsException{
// TODO Auto-generated method stub
System.out.println("调用init方法进行成员变量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
publicvoidclose(){
System.out.println("bean被销毁");
}
@Override
publicvoiddestroy()throwsException{
// TODO Auto-generated method stub
System.out.println("bean被销毁完成");
}
}
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- <bean id="init" class="com.model.InitBean" init-method="init"/> -->
<!-- <bean id="init" class="com.model.InitBean" destroy-method="close"/> -->
<beanid="init"class="com.model.InitBean"/>
</beans>
Spring Bean 的作用域 | 作用域 | 描述 |
|---|---|
| singleton | 该作用域将 bean 的定义的限制在每一个 Spring IoC 容器中的一个单一实例(默认)。 |
| prototype | 该作用域将单一 bean 的定义限制在任意数量的对象实例。 |
| request | 该作用域将 bean 的定义限制为 HTTP 请求。只在 web-aware Spring ApplicationContext 的上下文中有效。 |
| session | 该作用域将 bean 的定义限制为 HTTP 会话。 只在web-aware Spring ApplicationContext的上下文中有效。 |
| global-session | 该作用域将 bean 的定义限制为全局 HTTP 会话。只在 web-aware Spring ApplicationContext 的上下文中有效。 |
<bean id="..." class="..." scope="singleton"> </bean>
Bean 正常情况下,如果singleton作用域依赖singleton作用域。即每次获取到的都是一样的对象。同理,prototype作用域依赖prototype作用域,每次获取到的都是新的对象。但是,如果singleton依赖prototype作用域,那么每次获取到的singleton中的prototype都是第一次创建的prototype。如何协调这种关系。保证每次获取到的都是正确的呢。
对于这种情况, Spring 提供了 lookup 方法用来解决这种问题。
首先我们定义一个原型:
package com.model;
public classMyHelper{
publicvoiddoSomethingHelpful(){
}
}
然后通过接口注入:
package com.model;
public interfaceDemoBean{
MyHelpergetHelper();
voidsomePeration();
}
配置一个单例:
package com.model;
/**
* 测试类
* @author kevin
*
*/
public abstract classAbstractLookupDemoimplementsDemoBean{
publicabstractMyHelpergetMyHelper();
@Override
publicMyHelpergetHelper(){
// TODO Auto-generated method stub
return getMyHelper();
}
@Override
publicvoidsomePeration(){
// TODO Auto-generated method stub
}
}
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<beanid="helper"class="com.model.MyHelper"scope="prototype"/>
<beanid="standardLookupBean"class="com.model.StandardLookupDemo">
<propertyname="myHelper"ref="helper"></property>
</bean>
<beanid="abstractLookupBean"class="com.model.AbstractLookupDemo">
<lookup-methodname="getMyHelper"bean="helper"></lookup-method>
</bean>
</beans>
加载配置文件:
package com.model;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.StopWatch;
public classMain{
publicstaticvoidmain(String[] args){
AbstractApplicationContext context = new ClassPathXmlApplicationContext("lookBean.xml");
context.registerShutdownHook();
System.out.println("传递standardLookupBean");
test(context, "standardLookupBean");
System.out.println("传递AbstractLookupDemo");
test(context, "abstractLookupBean");
}
publicstaticvoidtest(AbstractApplicationContext context,String beanName){
DemoBean bean = (DemoBean) context.getBean(beanName);
MyHelper helper1 = bean.getHelper();
MyHelper helper2 = bean.getHelper();
System.out.println("测试"+beanName);
System.out.println("两个helper是否相同?"+(helper1==helper2));
StopWatch stopWatch = new StopWatch();
stopWatch.start("lookupDemo");
for (int i = 0; i < 10000; i++) {
MyHelper helper = bean.getHelper();
helper.doSomethingHelpful();
}
stopWatch.stop();
System.out.println("获取10000次花费了"+stopWatch.getTotalTimeMillis()+"毫秒");
}
}
结果:
从上面的结果图看出,以前的方式生成的对象每次都是相同的。通过lookup方式注入每次是不同的。可以解决这种问题。但是有没有更简单的方式,感觉这种方式优点麻烦。
Bean 感知 Spring 容器 实现 BeanNameAware ,自定设置 id 值。
实现 BeanFactoryAware , ApplicationContextAware 感知 Spring 容器。获取 Spring 容器。
Spring 国际化支持 <?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<beanid="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource">
<propertyname="basenames">
<list>
<value>message</value>
</list>
</property>
</bean>
</beans>
message_zh_CN.properties :
hello=welcome,{0}
now=now is : {0}
message_en_US.properties :
hello=/u4F60/u597D,{0}
now=/u73B0/u5728/u7684/u65F6/u95F4/u662F : {0}
package com.model;
import java.util.Date;
import java.util.Locale;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.StopWatch;
public classMain{
publicstaticvoidmain(String[] args){
ApplicationContext context = new ClassPathXmlApplicationContext("globalization.xml");
String[] a = {"读者"};
String hello = context.getMessage("hello",a, Locale.CHINA);
Object[] b = {new Date()};
String now = context.getMessage("now",b, Locale.CHINA);
System.out.println(hello);
System.out.println(now);
hello = context.getMessage("hello",a, Locale.US);
now = context.getMessage("now",b, Locale.US);
System.out.println(hello);
System.out.println(now);
}
}