Spring Bean 封装机制学习笔记
Spring 从核心而言是一个DI(依懒注入)容器,其设计是一种无入侵性的高扩展框架,即无需代码中涉及Spring专有类,即可将其纳入Spring容易进行管理。org.springframework.beans包中包括了这些核心组件的实现类。核心中的核心为BeanWrapper和BeanFactory类,从技术角度来说这两个类并不复杂。
1、Bean Wrapper
这个BeanWrapper类很简单,提供了一套Bean的操作方法,如apache -BeanUtils一样。通过BeanWrapper,我们可以无需在编码时就指定JavaBean的实现类和属性值,通过在配置文件
加以设定,就可以在运行期动态创建对象并设定其属性(依赖关系)。 一个简单的例子:
public
static
void
testBeanWrapper(){
try {
Object obj = Class.forName( " com.spring.UpperAction " ).newInstance();
BeanWrapper bw = new BeanWrapperImpl(obj);
bw.setPropertyValue( " message " , " peidw " );
System.out.println(bw.getPropertyValue( " message " ));
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Object obj = Class.forName( " com.spring.UpperAction " ).newInstance();
BeanWrapper bw = new BeanWrapperImpl(obj);
bw.setPropertyValue( " message " , " peidw " );
System.out.println(bw.getPropertyValue( " message " ));
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
2、Bean Factory
BeanFactory负责根据配置配置文件创建Bean实例,可以配置的项目有:
1 、Bean属性值及依赖关系
2、Bean创建模式(是否单态模式)
3、Bean初始化及销毁
4、Bean的依赖关系
<
beans
>
< description > Spring Bean Configuration Sample </ description >
< bean
id = " TheAction " ⑴
class = " net.xiaxin.spring.qs.UpperAction " ⑵
singleton = " true " ⑶
init - method = " init " ⑷
destroy - method = " cleanup " ⑸
depends - on = " ActionManager " ⑹
>
< property name = " message " >
< value > HeLLo </ value > ⑺
</ property >
< property name = " desc " >
< null />
</ property >
< property name = " dataSource " >
< ref local = " dataSource " /> ⑻
</ property >
</ bean >
< bean id = " dataSource "
class = " org.springframework.jndi.JndiObjectFactoryBean " >
< property name = " jndiName " >
< value > java:comp / env / jdbc / sample </ value >
</ property >
</ bean >
这是一个比较完整的Bean配置,id表示一个类在BeanFactory中的唯一标识
< description > Spring Bean Configuration Sample </ description >
< bean
id = " TheAction " ⑴
class = " net.xiaxin.spring.qs.UpperAction " ⑵
singleton = " true " ⑶
init - method = " init " ⑷
destroy - method = " cleanup " ⑸
depends - on = " ActionManager " ⑹
>
< property name = " message " >
< value > HeLLo </ value > ⑺
</ property >
< property name = " desc " >
< null />
</ property >
< property name = " dataSource " >
< ref local = " dataSource " /> ⑻
</ property >
</ bean >
< bean id = " dataSource "
class = " org.springframework.jndi.JndiObjectFactoryBean " >
< property name = " jndiName " >
< value > java:comp / env / jdbc / sample </ value >
</ property >
</ bean >
class 是java类名,singleton 为true表示使用单态,init-method初始化方法在BeanFactory创建Bean后执行的初始化方法。destroy-method销毁方法,在bean销毁时执行,一般用于资源释放。depends-on Bean的依懒关系。<value>节点用于指定一个属性值,ref节点用于引用另一个bean的属性。
联合上面关于BeanWrapper的内容,我们可以看到,BeanWrapper实现了针对单个Bean的属性设定操作。而BeanFactory则是针对多个Bean的管理容器,根据给定的配置文件,BeanFactory从中读取类名、属性名/值,然后通过Reflection机制进行Bean加载和属性设定。
3、ApplicationContext
BeanFactory提供了针对Java Bean的管理功能,而ApplicationContext提供了一个更为框架化的
实现(从上面的示例中可以看出,BeanFactory的使用方式更加类似一个API,而非Framework style)。
ApplicationContext覆盖了BeanFactory的所有功能,并提供了更多的特性。此外,
ApplicationContext为与现有应用框架相整合,提供了更为开放式的实现(如对于Web应用,我们可以在
web.xml中对ApplicationContext进行配置)。
相对BeanFactory而言,ApplicationContext提供了以下扩展功能:
1. 国际化支持
我们可以在Beans.xml文件中,对程序中的语言信息(如提示信息)进行定义,将程序中的提示
信息抽取到配置文件中加以定义,为我们进行应用的各语言版本转换提供了极大的灵活性。
2. 资源访问
支持对文件和URL的访问。
3. 事件传播
事件传播特性为系统中状态改变时的检测提供了良好支持。
4. 多实例加载
可以在同一个应用中加载多个Context实例。
一个国际化支持例子
public
static
void
testLanguage(){
ApplicationContext ac = new FileSystemXmlApplicationContext( " src/bean.xml " );
Object[] arg = new Object[]{ " kkui " ,Calendar.getInstance().getTime()};
// 以系统默认的Locale加载信息(对winxp而言默认的是zh_CN)
String zhmsg = ac.getMessage( " userinfo " ,arg, Locale.CHINA);
String usmsg = ac.getMessage( " userinfo " ,arg, Locale.US);
System.out.println(zhmsg);
System.out.println(usmsg);
}
需要在beans.xml文件配置使用多资源
ApplicationContext ac = new FileSystemXmlApplicationContext( " src/bean.xml " );
Object[] arg = new Object[]{ " kkui " ,Calendar.getInstance().getTime()};
// 以系统默认的Locale加载信息(对winxp而言默认的是zh_CN)
String zhmsg = ac.getMessage( " userinfo " ,arg, Locale.CHINA);
String usmsg = ac.getMessage( " userinfo " ,arg, Locale.US);
System.out.println(zhmsg);
System.out.println(usmsg);
}
<
bean
id
="messageSource"
class
="org.springframework.context.support.ResourceBundleMessageSource"
>
< property name ="basenames" >
< list >
< value > messages </ value >
</ list >
</ property >
</ bean >
这里声明了一个名为messageSource的Bean(注意对于Message定义,Bean ID必须为
< property name ="basenames" >
< list >
< value > messages </ value >
</ list >
</ property >
</ bean >
messageSource,这是目前Spring的编码规约),对应类为ResourceBundleMessageSource,
目前Spring中提供了两个MessageSource接口的实现,即
ResourceBundleMessageSource和ReloadableResourceBundleMessageSource,后
者提供了无需重启即可重新加载配置信息的特性。
资源文件message_zh.properties
userinfo=登陆用户:[{0}] 登陆时间[{1}]
国际化支持在实际开发中可能是最常用的特性。对于一个需要支持不同语言环境的应用而言,我们所采取的最常用的策略一般是通过一个独立的资源文件(如一个properties文件)完成所有语言信息(如界面上的提示信息)的配置,Spring对这种传统的方式进行了封装,并提供了更加强大的功能.
资源访问例子
Resource rs = ctx.getResource("classpath:config.properties");
File file = rs.getFile();
事件传播机制例子
File file = rs.getFile();
ApplicationContext基于Observer模式(java.util包中有对应实现),提供了针对Bean的事件传播功能。通过Application. publishEvent方法,我们可以将事件通知系统内所有的ApplicationListener。下面是一个例子:
package
com.spring;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
public class LoginAction implements ApplicationContextAware{
private ApplicationContext ac;
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
// TODO Auto-generated method stub
this .ac = arg0;
}
public int login(String username,String password){
ActionEvent ae = new ActionEvent(username);
this .ac.publishEvent(ae);
return 0 ;
}
}
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
public class LoginAction implements ApplicationContextAware{
private ApplicationContext ac;
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
// TODO Auto-generated method stub
this .ac = arg0;
}
public int login(String username,String password){
ActionEvent ae = new ActionEvent(username);
this .ac.publishEvent(ae);
return 0 ;
}
}
package
com.spring;
import org.springframework.context.ApplicationEvent;
public class ActionEvent extends ApplicationEvent {
public ActionEvent(Object source) {
super (source);
}
}
import org.springframework.context.ApplicationEvent;
public class ActionEvent extends ApplicationEvent {
public ActionEvent(Object source) {
super (source);
}
}
package
com.spring;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class ActionListener implements ApplicationListener{
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ActionEvent){
System.out.println(event.toString());
}
}
}
需要在beans.xml文件里添加以下配置
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class ActionListener implements ApplicationListener{
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ActionEvent){
System.out.println(event.toString());
}
}
}
<bean id
=
"
loginaction
"
class
=
"
net.xiaxin.beans.LoginAction
"
/>
<bean id = " listener " class = " net.xiaxin.beans.ActionListener " />
测试方法:
<bean id = " listener " class = " net.xiaxin.beans.ActionListener " />
public
static
void
testListener(){
ApplicationContext ac = new FileSystemXmlApplicationContext( " src/bean.xml " );
LoginAction la = (LoginAction)ac.getBean( " loginaction " );
la.login( " peidw " , " 123456 " );
}
Struts in SpringApplicationContext ac = new FileSystemXmlApplicationContext( " src/bean.xml " );
LoginAction la = (LoginAction)ac.getBean( " loginaction " );
la.login( " peidw " , " 123456 " );
}
Struts和Spring是如何整合,为了在struts加加载Spring Context;在struts-config.xml文件中添加以下配置
<
struts-config
>
< plug-in
className ="org.springframework.web.struts.ContextLoaderPlugIn" >
< set-property property ="contextConfigLocation"
value ="/WEB-INF/applicationContext.xml" />
</ plug-in >
</ struts-config >
通过plug-in我们实现了Spring Context的加载,不过仅仅加载Context并没有什么实际意义,我们还需要修改配置,将Struts Action交给Spring容器进行管理:
< plug-in
className ="org.springframework.web.struts.ContextLoaderPlugIn" >
< set-property property ="contextConfigLocation"
value ="/WEB-INF/applicationContext.xml" />
</ plug-in >
</ struts-config >