首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Web前端 >

Spring在web项目中配备的几种方式的分析

2012-10-19 
Spring在web项目中配置的几种方式的分析1、 配置在web.xml中a) 定义成listenelistenerlistener-classor

Spring在web项目中配置的几种方式的分析

1、 配置在web.xml中
a) 定义成listene
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener

</listener-class>
</listener>
b) 定义成servlet
<servlet>
????? <servlet-name>SpringContextServlet</servlet-name>
????? <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
????? <load-on-startup>1</load-on-startup>
?? </servlet>
?c) Web 容器会自动加载 /WEB-INF/applicationContext.xml 初始化 ApplicationContex t实例;
也可以通过
?? <context-param>
????? <param-name>contextConfigLocation</param-name>
????? <param-value>/WEB-INF/applicationContext-*.xml</param-value>
?? </context-param>
contextConfigLocation是Spring好像是默认加载的名称(下次读读Spring的源代码看看)
使 Web 容器加载指定名称路径的 Spring 配置文件。
这里涉及一个选择的问题,参考文献1中认为Listerner要比Servlet更好一些,因为Listerner监听应用的启动和结束,而Servlet得启动要稍微延迟一些,如果在这时要做一些业务的操作,启动的前后顺序是有影响的。
?关于Listerner和Servlet的区别我还不了解,还要去找找看到底区别在哪里。在我们项目中是放在Servlet里面设置的。
2、 配置为Struts的plungin
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
??????? <set-property property="contextConfigLocation"
??????????? value="/WEB-INF/applicationContext.xml,
?????????????????? /WEB-INF/action-servlet.xml"/>
??? </plug-in>
不过这类的用法比较不常见,而且他和Struts结合太紧,如果要做单元测试起来有点困难。

两者方式都是把Spring的WebApplicationContext放入到web的ServeletContext中,在web项目里面只要能拿到ServeletContext的地方都能使用。这里需要注意的是两者放入web ServeletContext时候的key是不一样的。前者是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,后者是ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX+ModuleConfig.getPrefix()。不过前者可以用WebApplicationContextUtils在ServeletContext把WebApplicationContext取出来,后者没有使用过,不是很了解。

上面说道要做单元测试,所以把Spring设置成Struts的plugin有点不方便,这个可以看看我们项目里面的使用。
在项目启动的时候我们做了Struts的plugin:ApplicationInitializer,在这里初始化一些全局变量,这个有点类似程序的main函数。在这里面:
ApplicationContext context = WebApplicationContextUtils.
??????????? getRequiredWebApplicationContext(this.actionServlet.getServletContext());
??????? // init ServiceLocator
??????? ServiceLocator.init(new SpringBeanHolder(context));
这里可以看到我们取出了ApplicationContext初始化一个ServiceLocator,以后我们的web都只是和ServiceLocator打交道,这里设置ApplicationContext只是在一个地方,如果以后要换IOC容器也比较方便,这里是不是一个代理模式呢?

不过这里很奇怪的有可以看见一个SpringBeanHolder,为什么会是这个样子呢?我们来看看ServiceLocator.init()的定义
public synchronized static void init(BeanHolder beanHolder){
??????? singleton = new ServiceLocator(beanHolder);
}
可以看到参数是BeanHolder,这个是一个接口:
public interface BeanHolder {
?public Object getBean(String beanId);
}
Look,这里就是把接口和实现分离了,以后如果不使用Spring了,好,那我们换一个实现,比如叫CrabBeanHolder :)
不过SpringBeanHolder也很简单:
public class SpringBeanHolder implements BeanHolder {
??? private ApplicationContext context;

??? public SpringBeanHolder(){}

??? public SpringBeanHolder(ApplicationContext context){
??????? this.context = context;
??? }

??? public Object getBean(String beanId){
??????? return context.getBean(beanId);
??? }
}

我们再去look一下ServiceLocator:
public class ServiceLocator {
??? private static Log log = LogFactory.getLog(ServiceLocator.class);
??? private BeanHolder beanHolder;
??? private static ServiceLocator singleton = null;

??? private ServiceLocator(){

??? }

??? private ServiceLocator(BeanHolder sh){
??????? this.setServiceHolder(sh);
??? }

??? public synchronized static void init(BeanHolder beanHolder){
??????? singleton = new ServiceLocator(beanHolder);
??? }

??? public static ServiceLocator getInstance(){
??????? return singleton;
??? }

??? private void setServiceHolder(BeanHolder beanHolder){
??????? this.beanHolder = beanHolder;
??? }
???
?public Object getBean(String beanId){
? return this.beanHolder.getBean(beanId);
?}

?public MasterFacade getMasterFacade(){
? return (MasterFacade)getBean("masterFacade");

可以看到他本来是想写一个单例模式,但是最后没有做限制,只要你做init方法,都会new一个,虽然我们只是使用一个,但是这里不作一个正规的if (singleton== null)的判断总是不太好,起码new也是一个开销啊。而且垃圾回收也是一个开销。记下来,下次改正。
不过在我们的web应用中也只是在ApplicationInitializer中做一下init,所以也算是单例啦:)

我们项目中还有一个ComponentManager:
public class ComponentManager {

?private ComponentManager() {
?
?}
?
?public static DataAccessStrategy getDataAccessStrategy(){
? return (DataAccessStrategy)ServiceLocator.getInstance().getBean("dataAccessStrategy");
?}
?
?public static DataSource getDataSource(){
? return (DataSource)ServiceLocator.getInstance().getBean("SPSDataSource");
?}
?
?public static MetadataManager getMetadataManager(){
???? return (MetadataManager)ServiceLocator.getInstance().getBean("metadataManager");
?}
?
?public static Object getBean(String beanId){
? return ServiceLocator.getInstance().getBean(beanId);
?}
}

这里他也是调用了ServiceLocator。其实两者的功能是一样的,上次我们的开发经理提过让我们注意两者的区别,我想这里的区别主要是语义上面的,ServiceLocator主要是直接定位各种业务Fa?ade他们都用直接的函数取得。而ComponentManager主要是去一些细颗粒度的bean把。
另外,在单元测试代码中,我们是这么使用ServiceLocator的:
String[] configLocations =
? {"/WEB-INF/spring-context-common.xml",
??????????????? "/WEB-INF/spring-context-master.xml",
??? "/WEB-INF/spring-context-inventory.xml",
??????????????? "/WEB-INF/spring-context-product.xml",
??? "/WEB-INF/spring-context-open.xml","/WEB-INF/spring-context-order.xml","/WEB-INF/spring-context-group.xml"};
???????
??????? ServiceLocator.init(new SpringBeanHolder
??????? (new FileSystemXmlApplicationContext(configLocations)));

??????? openProductFacade = (OpenProductFacade) ServiceLocator.getInstance().getOpenProductFacade();
看看这样是不是很方便,如果配置成为Struts的plungin的话测试的代码还要重新写,这样就不符合DRY(Don’t Repeat Yourself)的原则了。
今天总算是把项目中Struts和Spring结合的这个部分搞清楚了*^_^*,以前不清不楚的也可以做开发,而且也完成了两个项目了,但是这样总是不可以的,到时候碰到问题的时候都不知道怎么去解决呢。而且某某人说过一句:只是用一件东西,不彻底把他搞清楚怎么可以呢。
参考文献:
1、spring阶段性的一点感受 <http://www.360doc.com/showWeb.aspx?ArticleID=5484>

?

热点排行