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结合的这个部分搞清楚了*^_^*,以前不清不楚的也可以做开发,而且也完成了两个项目了,但是这样总是不可以的,到时候碰到问题的时候都不知道怎么去解决呢。而且某某人说过一句:只是用一件东西,不彻底把他搞清楚怎么可以呢。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值