开发者社区> walb呀> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

rose分析

简介:
+关注继续查看
最简单的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中。

本文转自博客园沉睡森林@漂在北京的博客,原文链接:rose分析,如需转载请自行联系原博主。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
robot_pose_ekf运行报错问题解决
robot_pose_ekf运行报错问题解决
89 0
spring boot 2.0 源码分析(四)
在上一章的源码分析里,我们知道了spring boot 2.0中的环境是如何区分普通环境和web环境的,以及如何准备运行时环境和应用上下文的,今天我们继续分析一下run函数接下来又做了那些事情。先把run函数的代码贴出来: /** * Run the Spring applicat...
1368 0
Spring Roo 命令行说明
参考文档:http://projects.spring.io/spring-roo/#running-from-shell $ roo.sh _ ___ ...
905 0
spring boot 登录注册 demo (四) -- 体验小结
之前没有折腾过Spring,直接上来怼Spring Boot异常痛苦,参考着官网的guide(https://spring.io/guides)写了几个demo; spring boot 跑起来确是方便,有种python的感觉,几行代码就可以起一个web服务,还不用自己去配置tomcat之类的; 于是尝试学习一下,目标就是写了一个注册登录的web页面出来,数据需要存放在DB中,这么一个简单的需求; 就是这么一个简单的demo折腾了好几天,虽然spring的资料很多,但零零碎碎的,本以为有很多登录注册的demo,然而并没有,不过索性是成功了。
725 0
Spring Ioc 源码分析(二)--refresh()
1.目标: 这篇记录debug 追溯源码的过程,大概分三个篇幅,这是第一篇,现整体了解一下运行流程,定位资源加载,资源解析,bean 注册发生的位置。 2.记录结构: 1.调试栈截图 2.整体流程 3.bean.xml的处理每段代码下面有相应的讲解 1.调试栈截图 屏幕快照 2016-10-24 下午6.51.56.png 每个栈帧中方法的行号都有标明,按照行号追溯源码,然后配合教程能够快速学习。
642 0
MapReduce源码分析之JobSplitWriter
        JobSplitWriter被作业客户端用于写分片相关文件,包括分片数据文件job.split和分片元数据信息文件job.splitmetainfo。它有两个静态成员变量,如下: // 分片版本,当前默认为1 private static final int splitVersion = JobSplit.
621 0
+关注
1038
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载