`

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);
    }
分享到:
评论

相关推荐

    Rosemirrorha

    通常在初始化的时候,需要采用完全镜像的方式。 差分镜像:只传输Standby与Active不同的部分,而不必传送相同部分的数据,可以减少对网络等资源的使用,提高数据镜像的效率。 按需复制性能资源最佳化 Rose...

    flash cs5运行时出现“java运行时环境初始化时出现错误”.pdf

    flash cs5运行时出现“java运行时环境初始化时出现错误”.pdf

    JobCenter::watch:让添加执行计划任务变得更加优雅〜Flask-Apscheduler工作中心:rose:

    特色:可视化界面操作定时任务统一管理完全兼容Crontab支持秒级定时任务作业任务可搜索,暂停,编辑,删除作业任务持久化存储,三种不同初始化类型作业动态添加 (注:demo版本部分功能已补充) :beer_mug: )用法:...

    SSH2项目(WeExam)源码

    3、打开一下连接初始化数据库:http://127.0.0.1:8080/WeExam/initialize 4、管理后台为:http://127.0.0.1:8080/admin_weexam/login.jsp 初始用户名密码为:admin 备注: UML文件夹内为rational rose的UML图。

    服务器集群设计说明.docx

    通常在初始化的时候,需要采用完全镜像的方式。差分镜像:只传输Standay与Active不同的部分,而不必传送相同部分的数据,可以减少对网络等资源的使用。减少不必要的网络传输,提高数据镜像的效率。 按需复制性能资源最佳...

    BookShop完整版.rar

    -- 初始化数据 INSERT INTO `user` (username,`password`,email,address) VALUES('admin','admin','admin@126.com','北京市海淀区'); INSERT INTO `user` (username,`password`,email,address) VALUES('jack','jack'...

    医院网络安全方案.doc

    完成整个切换过程,平 均时间为40秒,此时系统又进入初始状态。 1.4系统特点 硬件结合实现真正意义上的数据与系统分离。 对硬件配置要求不高,服务器可采用不同或相差较大的配置。 系统切换时间短,平均切换时间为...

    医院网络安全方案经典.doc

    完成整个切换过程, 平均时间为40秒,此时系统又进入初始状态。 1.4系统特点 硬件结合实现真正意义上的数据与系统别离。 对硬件配置要求不高,效劳器可采用不同或相差较大的配置。 系统切换时间短,平均切换时间为...

    数据库设计报告.pdf

    产品研发中心 ECSE ABC 实训项目-软件商城系统项目文档 Version 2.0 数据库设计文档 一,数据库命名规范 数据库名称: 软件商店的英语翻译为 Software-Shop,数据库的名称简写为 ...9 系统在初始化的时候设置系统信息 S

    图书管理系统软件工程课程设计(1).doc

    "数据项名 "出版社 " "取 值 "0-20字符 " (三)加工说明 审查用户查询书籍信息请求 2.3图-加工说明 (四)结构图 图2.4-1—图书管理系统上层框架 图2.4-2-图书管理子系统初始SC图 图2.4-3-图书管理子系统初始SC图 ...

    图书管理系统软件工程课程设计.doc

    "数据项名 "出版社 " "取 值 "0-20字符 " (三)加工说明 审查用户查询书籍信息请求 2.3图-加工说明 (四)结构图 图2.4-1—图书管理系统上层框架 图2.4-2-图书管理子系统初始SC图 图2.4-3-图书管理子系统初始SC图 ...

    LINGO软件的学习

    现在我们将深入介绍如何创建集,并用数据初始化集的属性。学完本节后,你对基于建模技术的集如何引入模型会有一个基本的理解。 2.1 为什么使用集 集是LINGO建模语言的基础,是程序设计最强有力的基本构件。借助于集...

    MATLAB软件中乘法代码-FastBTTB:具有块Toeplitz的矩阵的快速乘法Toeplitz块结构

    建议初始运行,下限= 1,上限= 2,填充= 1。 这将验证代码是否正确运行。 然后以低比例= 1,高比例= 2,填充= 2运行。 这等效于添加了填充的运行。 最终运行(昂贵),下限= 1,上限= 12 (选择填充= 1表示无填充) ...

Global site tag (gtag.js) - Google Analytics