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

来源:百度文库 编辑:神马文学网 时间:2024/04/20 11:04:38

1、 配置在web.xml中
a) 定义成listene

     org.springframework.web.context.ContextLoaderListener
 

b) 定义成servlet

      SpringContextServlet
      org.springframework.web.context.ContextLoaderServlet
      1
  

 c) Web 容器会自动加载 /WEB-INF/applicationContext.xml 初始化 ApplicationContex t实例;
也可以通过
  
      contextConfigLocation
      /WEB-INF/applicationContext-*.xml
  

contextConfigLocation是Spring好像是默认加载的名称(下次读读Spring的源代码看看)
使 Web 容器加载指定名称路径的 Spring 配置文件。
这里涉及一个选择的问题,参考文献1中认为Listerner要比Servlet更好一些,因为Listerner监听应用的启动和结束,而Servlet得启动要稍微延迟一些,如果在这时要做一些业务的操作,启动的前后顺序是有影响的。
 关于Listerner和Servlet的区别我还不了解,还要去找找看到底区别在哪里。在我们项目中是放在Servlet里面设置的。
2、 配置为Struts的plungin

                    value="/WEB-INF/applicationContext.xml,
                   /WEB-INF/action-servlet.xml"/>
   

不过这类的用法比较不常见,而且他和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阶段性的一点感受