【rose】rose初始化
rose封装了spring框架,集合spring IOC和AOP所构建的一个MVC框架
rose载体为RoseFilter
在web.xml配置文件,如filter进行配置即可,如下:
<
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>
RoseFilter
初始化函数:initFilterBean
初始化 rose的 context 容器
WebApplicationContext rootContext = prepareRootApplicationContext();
rose通过继承XmlWebApplicationContext,构建自己的context RoseWebAppContext 作为最根级别的 ApplicationContext 对象
RoseWebAppContext rootContext =
new RoseWebAppContext(getServletContext(), load , false);
rootContext.setConfigLocation(contextConfigLocation);
rootContext.setId(
"rose.root");
rootContext.refresh();
上述的 refresh 方法和spring的 context 的初始化过程一样,即IOC对象的初始化
调用refresh 方法后,就会把配置文件中的 bean 载入到内存,成为 BeanDefinition
rose下 会有如下配置文件的约定 /WEB-INF/applicationContext*.xml
所有形如该形式的.xml文件将会被rose所识别,并载入到IOC容器中
// 识别 Rose 程序模块
this.modules = prepareModules(rootContext);
rose 以 controllers 作为一个模块,controllers 下的package也会作为一个模块
模块对象 ModuleResource 封装了 controllers 相关的资源
包括模块路径,匹配的xml资源等
初始化过程通过 provider.findModuleResources( load) 进行资源的加载,构建 List<ModuleResource>
初始化过程会把模块里的 beandefinition 类加载到内存,并保存在ModuleResource
module.addModuleClass(Class. forName(className));
完成模块资源扫描后,就开始为每个具体的模块进行具体的资源搭配构建了
List<Module> modules = modulesBuilder. build(moduleResources, rootContext)
构建一个模块list,包括了rose的各个模块,即对rose的各个模块的初始化
单独的模块 Module 会构建自己的 context 对象
ServletContext servletContext = parent.getServletContext();
Assert. notNull(servletContext);
ModuleAppContext wac =
new ModuleAppContext();
wac.setParent(parent);
wac.setServletContext(servletContext);
wac.setContextResources( toResources(contextResources));
wac.setId(uniqueId);
wac.setNamespace(namespace);
wac.setMessageBaseNames(messageBasenames);
wac.refresh();
又看到 refresh 方法了,即初始化 Module 的context IOC容器
然后会把模块相关的bean 注册到模块的 IOC容器里
registerBeanDefinitions (moduleContext, moduleResource.getModuleClasses());
然后 rose 会把模块相关的 resolver interceptor等资源进行加载
// 从Spring应用环境中找出本web模块要使用的ParamValidator,ParamResolver, ControllerInterceptor, ControllerErrorHandler
List<ParamResolver> customerResolvers = findContextResolvers(moduleContext);
List<InterceptorDelegate> interceptors = findContextInterceptors(moduleContext);
List<ParamValidator> validators = findContextValidators(moduleContext);
ControllerErrorHandler errorHandler = getContextErrorHandler(moduleContext);
找出关联的资源,然后会加载到module 中
module.addCustomerResolver(resolver);
module.addControllerInterceptor(interceptor);
module.addValidator(validator);
module.setErrorHandler(errorHandler);
对于interceptor 的加载如下
for
( int i = 0; i < interceptors .size(); i++) {
// 先判断是否有"名字"一样的拦截器
InterceptorDelegate temp =
interceptors.get(i);
if (temp.getName().equals(interceptor.getName())) {
// rose内部要求interceptor要有一个唯一的标识
// 请这两个类的提供者商量改类名,不能同时取一样的类名
// 如果是通过@Component等设置名字的,则不要设置一样
ControllerInterceptor duplicated1 = InterceptorDelegate
. getMostInnerInterceptor(temp);
ControllerInterceptor duplicated2 = InterceptorDelegate
. getMostInnerInterceptor(interceptor);
throw new IllegalArgumentException(
"duplicated interceptor name for these two interceptors: '"
+ duplicated1.getClass() +
"' and '" + duplicated2.getClass() + "'" );
}
// 加入到这个位置?
if (!added && interceptor.getPriority() > temp.getPriority()) {
this.interceptors .add(i, interceptor);
added =
true;
}
}
拦截器的优先级即通过 if (!added && interceptor.getPriority() > temp.getPriority()) 这个语句进行判断
然后把拦截器加载到适当的位置
加载完相关的资源后,rose才对controller进行初始化,对模块里的各个 controller 进行初始化
for
(String beanName : beanFactory.getBeanDefinitionNames()) {
checkController(moduleContext, beanName, module);
}
在初始化过程中,可以看到以下的语句:
Path
reqMappingAnnotation = clazz.getAnnotation(Path.class);
if (reqMappingAnnotation != null) {
controllerPaths = reqMappingAnnotation.value();
}
我们在 controller 上标注的@Path 注解,在这里得到了解析,作为controller 的新路径
另外可以看到如下语句,rose 约定,controller 的命名规范
//
TODO: 这个代码是为了使从0.9到1.0比较顺畅而做的判断,201007之后可以考虑删除掉
if (controllerName.equals("index" ) || controllerName.equals("home" )
|| controllerName.equals(
"welcome")) {
// 这个异常的意思是让大家在IndexController/HomeController/WelcomeController上明确标注@Path("")
throw new IllegalArgumentException("please add @Path(\"\") to " + clazz.getName());
}
else {
controllerPaths =
new String[] { "/" + controllerName };
}
然后 rose 从context 里得到 controller 实例,没有对 controller 进行属性的标注,就是单例了
Object controller = context.getBean(beanName);
module. addController(
//
controllerPaths, clazz, controllerName, controller);
添加 controller 实例到module 里
这样一个 module 就填充完成了
完成了资源的加载后就到了 另一个关键的步骤了,即rose的匹配树的构建过程
// 创建匹配树以及各个结点的上的执行逻辑(Engine)
this.mappingTree = prepareMappingTree(modules);
rose构建一个根节点,然后从根节点进行枝叶的添加
Mapping rootMapping =
new ConstantMapping( "");
MappingNode mappingTree =
new MappingNode(rootMapping);
LinkedEngine rootEngine =
new LinkedEngine(null, new RootEngine(instructionExecutor ),
mappingTree);
mappingTree.getMiddleEngines().addEngine(ReqMethod.
ALL, rootEngine);
TreeBuilder treeBuilder =
new TreeBuilder();
treeBuilder.create(mappingTree, modules);
构建过程由 create 方法开始
整个构建过程为先从 module 开始,一个一个路径添加到匹配树上
for
(Module module : modules) {
addModule(rootNode, module);
}
然后把controllers 的路径添加到匹配树上
for
(ControllerRef controller : controllers) {
addController(module, parent, moduleEngine, controller);
}
最后把 action 方法的路径添加到匹配树上
for
(MethodRef action : actions) {
addAction(module, controller, action, target, controllerEngine);
}
在把 controllers 的action 方法添加到匹配树上前,rose会对 controllers 进行初始化操作
如下,标注了 @Get @Post的方法会得到处理,解析并获取标注的路径值
for
(Annotation annotation : annotations) {
if (annotation instanceof Delete) {
restMethods.put(ReqMethod.
DELETE, ((Delete ) annotation).value());
}
else if (annotation instanceof Get) {
restMethods.put(ReqMethod.
GET, ((Get ) annotation).value());
}
else if (annotation instanceof Head) {
restMethods.put(ReqMethod.
HEAD, ((Head ) annotation).value());
}
else if (annotation instanceof Options) {
restMethods.put(ReqMethod.
OPTIONS, ((Options ) annotation).value());
}
else if (annotation instanceof Post) {
restMethods.put(ReqMethod.
POST, ((Post ) annotation).value());
}
else if (annotation instanceof Put) {
restMethods.put(ReqMethod.
PUT, ((Put ) annotation).value());
}
else if (annotation instanceof Trace) {
restMethods.put(ReqMethod.
TRACE, ((Trace ) annotation).value());
}
else {}
}
for (String[] paths : restMethods.values()) {
for (int i = 0; i < paths.length; i++) {
String path = paths[i];
if (path.length() > 0 && path.charAt(0) != '/') {
paths[i] =
"/" + path;
}
}
}
如下,rose 做了约定,凡是使用index/get等的方法名的必须添加注解
否则rose会抛出异常
//
TODO: 这个代码是为了使从0.9到1.0比较顺畅而做的判断,201007之后可以考虑删除掉
if ("get" .equals(method.getName()) || "index".equals(method.getName())) {
// 这个异常的意思是让大家在get/index上明确标注@Get,请注意@Get的意思
throw new IllegalArgumentException("please add @Get to "
+
controllerClass.getName() + "#" + method.getName());
}
if ("post" .equals(method.getName()) || "delete".equals(method.getName())
||
"put".equals(method.getName())) {
// 这个异常的意思是让大家在post/delete/put上明确标注@Get/@Delete/@Put,请注意@Get的意思
throw new IllegalArgumentException("please add @"
+ StringUtils.capitalize(method.getName()) +
" to "
+
controllerClass.getName() + "#" + method.getName());
}
如果方法没有标注任何注解,则 rose会使用默认操作
方法会默认可以处理get、post请求,请求路径名为方法名
shotcutMappings.put(ReqMethod.
GET, new String[] { "/" + method.getName() });
shotcutMappings
.put(ReqMethod.
POST, new String[] { "/" + method.getName() });
另外,对于标注了 @AsSuperController 注解的 controller 类,其子类可以使用父类的action方法
其处理过程如下,rose 会解析注解,标注该注解则会 解析父类的action方法,并添加到匹配树中
clz = clz.getSuperclass();
if (clz == null || clz.getAnnotation(AsSuperController .class) == null) {
break;
}
// 初始化完成后,就可以通过addAction 添加 controller的方法了
// 而addAction方法里有下面的逻辑
Engine actionEngine =
new
ActionEngine(module, controller.getControllerClass(),
//
controller.getControllerObject(), action.getMethod());
// 初始化actionEngine对象
public
ActionEngine(Module module, Class<?> controllerClass, Object controller, Method method) {
this
.
module
= module;
this
.
controllerClass
= controllerClass;
this
.
controller
= controller;
this
.
method
= method;
this
.
interceptors
= compileInterceptors ();
this
.
methodParameterResolver
= compileParamResolvers();
this
.
validators
= compileValidators();
this
.
acceptedCheckers
= compileAcceptedCheckers();
}
// 这里可以看到这该方法下的连接器的初始化
private
InterceptorDelegate[] compileInterceptors () {
List<InterceptorDelegate> interceptors =
module
.getInterceptors();
List<InterceptorDelegate> registeredInterceptors =
new
ArrayList<InterceptorDelegate>(
interceptors.size());
for
(InterceptorDelegate interceptor : interceptors) {
// 获取@Intercepted注解 (@Intercepted注解配置于控制器或其方法中,决定一个拦截器是否应该拦截之。没有配置按“需要”处理)
Intercepted
intercepted =
method
.getAnnotation(
Intercepted
.
class
);
if
(intercepted ==
null
) {
// 对于标注@Inherited的annotation,class.getAnnotation可以保证:如果本类没有,自动会从父类判断是否具有
intercepted =
this
.
controllerClass
.getAnnotation(
Intercepted
.
class
);
}
// 通过@Intercepted注解的allow和deny排除拦截器
if
(intercepted !=
null
) {
// 3.1 先排除deny禁止的
if
(ArrayUtils.contains(intercepted.deny(),
"*"
)
|| ArrayUtils. contains(intercepted.deny(), interceptor.getName())) {
continue
;
}
// 3.2 确认最大的allow允许
else
if
(!ArrayUtils.contains (intercepted.allow(),
"*"
)
&& !ArrayUtils. contains(intercepted.allow(), interceptor.getName())) {
continue
;
}
}
// 取得拦截器同意后,注册到这个控制器方法中
if
(interceptor.isForAction(
controllerClass
,
method
)) {
registeredInterceptors.add(interceptor);
}
}
//
return
registeredInterceptors
.toArray(
new
InterceptorDelegate[registeredInterceptors.size()]);
}
// 我们知道拦截器可以通过使用注解来标注是否拦截一个请求的处理的
// 具体是否需要拦截,这个判断就是通过
interceptor.isForAction 这个方法来实现的
public
final
boolean
isForAction(Class<?> controllerClazz, Method actionMethod) {
// 返回false,表示控制器或其方法没有标注本拦截器所要求的注解
if
(!checkRequiredAnnotations(controllerClazz, actionMethod)) {
return
false
;
}
// 返回true,表示控制器或其方法标注了“拒绝”注解
if
(checkDenyAnnotations(controllerClazz, actionMethod)) {
return
false
;
}
return
isForAction(actionMethod, controllerClazz);
}