1、资源加载的触发点
在web应用中,spring容器的初始化是从ServletContextListener开始。大家知道ServletContextListener是配置在web.xml中。
<!-- 装载/WEB-INF/webx.xml, /WEB-INF/webx-*.xml --> <listener> <listener-class> com.alibaba.citrus.webx.context.WebxContextLoaderListener </listener-class> </listener>
从com.alibaba.citrus.webx.context.WebxContextLoaderListener的源码中我们可以看出他是继承自spring框架的
ContextLoaderListener 的。
public class WebxContextLoaderListener extends ContextLoaderListener {
@Override
protected final ContextLoader createContextLoader() {
return new WebxComponentsLoader() {
@Override
protected Class<?> getDefaultContextClass() {
Class<?> defaultContextClass = WebxContextLoaderListener.this.getDefaultContextClass();
if (defaultContextClass == null) {
defaultContextClass = super.getDefaultContextClass();
}
return defaultContextClass;
}
};
}
protected Class<?> getDefaultContextClass() {
return null;
}
}
这段代码我们可以看出以下spring初始化中关键的几点。
1.指定了spring上下文加载器ContextLoader是WebxComponentsLoader的匿名子类。
2.该匿名子类指定了默认的上下文Class同WebxComponentsLoader的一样。
接下来我们可以看到WebComponentssLoader的Class<?> getDefaultContextClass() 方法指定默认的WebApplicationContext是WebxComponentsContext
WebxComponentsContext的Type Hierachy如下图所示。
webx3中的com.alibaba.citrus.springext.support.context.XmlWebApplicationContext中支持扩展的resource loading机制。
通过重写protected Resource getResourceByPath(String path) 和protected ResourcePatternResolver getResourcePatternResolver() 两个方法完成了支持扩展ResourcePatternResolver机制(即:实现自定义的资源装载)。
另外该类还重写了 protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader),所以XmlBeanDefinitionReader可以自动的识别webx中的一些标签(其中就包括resource-loding)。
2.webx中的resource loading。
webx扩展了spring的resource loader。在spring配置文件中添加ResourceLoading服务时,ResourceLoader 即被切换到新的机制。新的机制可兼容原有的Spring配置和代码,但支持更多的资源装载方式,以及支持重命名、重定向资源。
当ResourceLoadingService收到资源加载的请求后,将通过ResourceMapping查找合适的ResourceLoader来加载资源。各类ResourceLoader会根据资源名称将资源加载进内存并转换为webx框架自定义的Resource。随后这些自定义resource将会被适配为spring框架中的Resource。
简单的类图关系如下:
3.resource loading的使用范例:
只要在webx.xml中添加resource-loading的配置,webx就会自动的将加载方式重spring的resource loader切换到resource loading。
3.1)重命名资源,取消资源名称和资源环境的相关性。
<resource-loading xmlns="http://www.alibaba.com/schema/services" xmlns:res-loaders="http://www.alibaba.com/schema/services/resource-loading/loaders"> ... <resource-alias pattern="/myapp/conf" name="/webroot/WEB-INF" /> <resource pattern="/webroot" internal="true"> <res-loaders:webapp-loader /> </resource> </resource-loading>
3.2)重定向资源
这个开发的时候用的最多,一般会将template资源指向开发目录下的template就可以了,这样每次修改后不需要重新部署就可以看到修改的效果。
<resource-loading xmlns="http://www.alibaba.com/schema/services" xmlns:res-loaders="http://www.alibaba.com/schema/services/resource-loading/loaders"> ... <resource pattern="/templates"> <res-loaders:file-loader basedir="${dev_root}/templates" /> </resource> ... </resource-loading>
当然貌似上边的资源重命名也可以实现这个功能。呵呵
3.3)通过通配符来匹配资源
ResourceLoading服务支持用通配符来匹配资源名称或资源别名(alias)。通配符定义如下,不过好像现在项目没有接触到用的地方。
a.“*”匹配0-n个字符,但不包括“/”。即,“*”只匹配一级目录或文件中的零个或多个字符
b.“**”匹配0-n个字符,包括“/”。即,“**”匹配多级目录或文件
c.“?”匹配0-1个字符,但不包括“/”。即,“?”匹配一级目录或文件中的零个或一个字符
所有的匹配,将被按顺序赋予变量“$1”、“$2”、“$3”、“$4”、……。这些变量可以在其它地方被引用。
3.4)特殊的super-loader
如果spring容器是多级的,默认的resource loading服务是现在当前容器查找资源如果不存在,那么去赴容器中查找。如此级联查找,如果都找不到,那么就放弃。
如果找到会返回第一个找到的结果。
如果要引用的资源知道在赴容器中那么就可以直接用这个super-loader,不过他默认的仍然是这样子查找只要不指定name就会直接去parent容器查找了。
我们也可以变更这个级联查找的顺序,比如要先在赴容器查找然后才在子容器查找,就可以这样配置了。
<resource pattern="/reverseLookup"> <!-- 先找parent容器中的ResourceLoading服务 --> <res-loaders:super-loader /> <!-- 再找当前容器中的ResourceLoader --> <res-loaders:file-loader /> </resource>