最简单的rose配置: < project xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns ="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > < modelVersion >4.0.0
</ modelVersion > < groupId >com.jiexi.demos
</ groupId > < artifactId >rose-demos
</ artifactId > < version >0.0.1-SNAPSHOT
</ version > < packaging >war
</ packaging > < dependencies > < dependency > < groupId >net.paoding
</ groupId > < artifactId >paoding-rose
</ artifactId > < version >1.0-SNAPSHOT
</ version > </ dependency > < dependency > < groupId >log4j
</ groupId > < artifactId >log4j
</ artifactId > < version >1.2.15
</ version > < exclusions > < exclusion > < artifactId >mail
</ artifactId > < groupId >javax.mail
</ groupId > </ exclusion > < exclusion > < artifactId >jms
</ artifactId > < groupId >javax.jms
</ groupId > </ exclusion > < exclusion > < artifactId >jmxtools
</ artifactId > < groupId >com.sun.jdmk
</ groupId > </ exclusion > < exclusion > < artifactId >jmxri
</ artifactId > < groupId >com.sun.jmx
</ groupId > </ exclusion > </ exclusions > </ dependency > </ dependencies > < build > < finalName >jeasyweb-framework
</ finalName > < plugins > < plugin > < groupId >org.apache.maven.plugins
</ groupId > < artifactId >maven-compiler-plugin
</ artifactId > < configuration > < source >1.6
</ source > < target >1.6
</ target > < encoding >UTF-8
</ encoding > </ configuration > </ plugin > < plugin > < groupId >org.mortbay.jetty
</ groupId > < artifactId >maven-jetty-plugin
</ artifactId > < version >6.1.26
</ version > < configuration > < contextPath >/
</ contextPath > < scanIntervalSeconds >10
</ scanIntervalSeconds > < stopKey >foo
</ stopKey > < stopPort >9998
</ stopPort > </ configuration > < executions > < execution > < id >start-jetty
</ id > < phase >pre-integration-test
</ phase > < goals > < goal >run
</ goal > </ goals > < configuration > < scanIntervalSeconds >0
</ scanIntervalSeconds > < daemon >true
</ daemon > </ configuration > </ execution > < execution > < id >stop-jetty
</ id > < phase >post-integration-test
</ phase > < goals > < goal >stop
</ goal > </ goals > </ execution > </ executions > </ plugin > </ plugins > </ build > </ project > <? xml version="1.0" encoding="utf-8" ?> < web-app xmlns ="http://java.sun.com/xml/ns/j2ee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd" version ="2.4" > < context-param > < param-name >log4jConfigLocation
</ param-name > < param-value >/WEB-INF/log4j.properties
</ param-value > </ context-param > < listener > < listener-class >org.springframework.web.util.Log4jConfigListener
</ listener-class > </ listener > < filter > < filter-name >roseFilter
</ filter-name > < filter-class >net.paoding.rose.RoseFilter
</ filter-class > </ filter > < filter-mapping > < filter-name >roseFilter
</ filter-name > < url-pattern >/*
</ url-pattern > < dispatcher >REQUEST
</ dispatcher > < dispatcher >FORWARD
</ dispatcher > < dispatcher >INCLUDE
</ dispatcher > </ filter-mapping > </ web-app > package com.jiexi.demos.rose.controllers;
import net.paoding.rose.web.annotation.Path;
import net.paoding.rose.web.annotation.rest.Get;
@Path("")
public class IndexController {
@Get("index")
public String index() {
return "index";
}
}
rose启动到底做了那些工作: @Override
protected final void initFilterBean()
throws ServletException {
try {
long startTime = System.currentTimeMillis();
if (logger.isInfoEnabled()) {
logger.info("[init] call 'init/rootContext'");
}
if (logger.isDebugEnabled()) {
StringBuilder sb =
new StringBuilder();
@SuppressWarnings("unchecked")
Enumeration<String> iter = getFilterConfig().getInitParameterNames();
while (iter.hasMoreElements()) {
String name = (String) iter.nextElement();
sb.append(name).append("='").append(getFilterConfig().getInitParameter(name))
.append("'\n");
}
logger.debug("[init] parameters: " + sb);
}
WebApplicationContext rootContext = prepareRootApplicationContext();
if (logger.isInfoEnabled()) {
logger.info("[init] exits from 'init/rootContext'");
logger.info("[init] call 'init/module'");
}
// 识别 Rose 程序模块 this.modules = prepareModules(rootContext);
if (logger.isInfoEnabled()) {
logger.info("[init] exits from 'init/module'");
logger.info("[init] call 'init/mappingTree'");
}
// 创建匹配树以及各个结点的上的执行逻辑(Engine) this.mappingTree = prepareMappingTree(modules);
if (logger.isInfoEnabled()) {
logger.info("[init] exits from 'init/mappingTree'");
logger.info("[init] exits from 'init'");
}
long endTime = System.currentTimeMillis();
// 打印启动信息 printRoseInfos(endTime - startTime);
// }
catch (
final Throwable e) {
StringBuilder sb =
new StringBuilder(1024);
sb.append("[Rose-").append(RoseVersion.getVersion());
sb.append("@Spring-").append(SpringVersion.getVersion()).append("]:");
sb.append(e.getMessage());
logger.error(sb.toString(), e);
throw new NestedServletException(sb.toString(), e);
}
}
2大核心功能: 功能1: /** * 创建最根级别的 ApplicationContext 对象,比如WEB-INF、WEB-INF/classes、 * jar中的spring配置文件所组成代表的、整合为一个 ApplicationContext 对象 * * @return * @throws IOException */ private WebApplicationContext prepareRootApplicationContext()
throws IOException {
if (logger.isInfoEnabled()) {
logger.info("[init/rootContext] starting
");
}
ApplicationContext oldRootContext = (ApplicationContext) getServletContext().getAttribute(
ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
// 如果web.xml配置使用了spring装载root应用context 不可以 // roseFilter可能因为启动失败,在请求的时候容器还会尝试重新启动,此时rootContext可能已经存在,不要简单地抛出异常 // 同时这样留出了使用Listener作为init rose context的扩展机会 if (oldRootContext !=
null) {
if (oldRootContext.getClass() != RoseWebAppContext.
class) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - "
+ "check whether you have multiple ContextLoader* definitions in your web.xml!");
}
if (logger.isInfoEnabled()) {
logger.info("[init/rootContext] the root context exists:" + oldRootContext);
}
return (RoseWebAppContext) oldRootContext;
}
RoseWebAppContext rootContext =
new RoseWebAppContext(getServletContext(), load,
false);
String contextConfigLocation =
this.contextConfigLocation;
// 确认所使用的applicationContext配置 if (StringUtils.isBlank(contextConfigLocation)) {
String webxmlContextConfigLocation = getServletContext().getInitParameter(
"contextConfigLocation");
if (StringUtils.isBlank(webxmlContextConfigLocation)) {
contextConfigLocation = RoseWebAppContext.DEFAULT_CONFIG_LOCATION;
}
else {
contextConfigLocation = webxmlContextConfigLocation;
}
}
rootContext.setConfigLocation(contextConfigLocation);
rootContext.setId("rose.root");
rootContext.refresh();
if (logger.isInfoEnabled()) {
logger.info("[init/rootContext] exits");
}
/* enable: WebApplicationContextUtils.getWebApplicationContext() */ getServletContext().setAttribute(ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, rootContext);
if (logger.isInfoEnabled()) {
logger.info("[init/rootContext] Published rose.root WebApplicationContext ["
+ rootContext + "] as ServletContext attribute with name ["
+ ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
return rootContext;
}
首先通过new直接创建WebApplicationContext,然后将其作为参数继续构建modules。可以看到参数contextConfigLocation的处理: String webxmlContextConfigLocation = getServletContext().getInitParameter(
"contextConfigLocation");
if (StringUtils.isBlank(webxmlContextConfigLocation)) {
contextConfigLocation = RoseWebAppContext.DEFAULT_CONFIG_LOCATION;
}
else {
contextConfigLocation = webxmlContextConfigLocation;
}
这里可以再web.xml里面定义参数,或者使用系统默认的参数:"/WEB-INF/applicationContext*.xml" 而对于main/resources/applicationContext *.xml 或者jar包里面的applicationContext*.xml文件的读取,是通过复写XmlWebApplicationContext的方法实现的: @Override
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader)
throws BeansException,
IOException {
Resource[] configResources = getConfigResourcesThrows();
if (configResources !=
null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations !=
null) {
for (
int i = 0; i < configLocations.length; i++) {
reader.loadBeanDefinitions(configLocations[i]);
}
}
}
功能2: private List<Module> prepareModules(WebApplicationContext rootContext)
throws Exception {
// 自动扫描识别web层资源,纳入Rose管理 if (logger.isInfoEnabled()) {
logger.info("[init/mudule] starting
");
}
ModuleResourceProvider provider = moduleResourceProviderClass.newInstance();
if (logger.isInfoEnabled()) {
logger.info("[init/module] using provider: " + provider);
logger.info("[init/module] call 'moduleResource': to find all module resources.");
logger.info("[init/module] load " + load);
}
List<ModuleResource> moduleResources = provider.findModuleResources(load);
if (logger.isInfoEnabled()) {
logger.info("[init/mudule] exits 'moduleResource'");
}
ModulesBuilder modulesBuilder = modulesBuilderClass.newInstance();
if (logger.isInfoEnabled()) {
logger.info("[init/module] using modulesBuilder: " + modulesBuilder);
logger.info("[init/module] call 'moduleBuild': to build modules.");
}
List<Module> modules = modulesBuilder.build(moduleResources, rootContext);
if (logger.isInfoEnabled()) {
logger.info("[init/module] exits from 'moduleBuild'");
logger.info("[init/mudule] found " + modules.size() + " modules.");
}
return modules;
}
rose在init时会读取controllers里面的以Controller结尾的类,通过prepareModules功能实现的。 这块功能较复杂,涉及到*Controller,*Interceptor,*ErrorHandler,rose.properties,messages等的读取配置。 这块功能具体实现了rose的约定大约配置的思想,默认读取package的配置对应到不同的module中。
本文转自博客园沉睡森林@漂在北京的博客,原文链接:,如需转载请自行联系原博主。