造一个方形的轮子1–嵌入容器

2019-06-20  本文已影响0人  爱笑笑_ixx

造一个方形轮子文章目录:造一个方形的轮子

01、引入容器依赖

先创建一个maven项目square,然后想一下,如果要自己造一下轮子那么第一步添加的功能是什么呢?
我的第一反应就是要像Springboot一样,单jar包启动,不用在打包单独部署到tomcat里了。
那么就需要为这个方形的轮子嵌入一个Web运行容器,就用现成的tomcat-embed就可以了
添加pom.xml引用:

    <properties>
        ......
        <tomcat-version>9.0.8</tomcat-version>
    </properties>

    <dependencies>
        ......
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>${tomcat-version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-util</artifactId>
            <version>${tomcat-version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <version>${tomcat-version}</version>
        </dependency>
    </dependencies>

02、创建启动类

然后创建一个我们的应用启动类:
SquareApplication.java:

public class SquareApplication {
    private static final Logger log = LoggerFactory.getLogger(SquareApplication.class);
    private static Tomcat tomcat = null;
    private static String CONTEXT_PATH = "/";
    private static String ENCODING = "UTF-8";
    private static int TOMCAT_PORT = 8080;

    public static void run(Class clzz, String[] args) {
        try {
            String project_path = clzz.getResource("").getPath();
            project_path = project_path.substring(0, project_path.indexOf("classes"));
            long startTime = System.currentTimeMillis();
            tomcat = new Tomcat();
            // 设置Tomcat的工作目录:工程根目录/Tomcat
            tomcat.setBaseDir(project_path + "/Tomcat");
            tomcat.setPort(TOMCAT_PORT);
            tomcat.addWebapp(CONTEXT_PATH, project_path);
            // 执行这句才能支持JDNI查找
            tomcat.enableNaming();
            tomcat.getConnector().setURIEncoding(ENCODING);
            tomcat.start();
            log.info("Tomcat started on port(s): {} with context path '{}'", TOMCAT_PORT, CONTEXT_PATH);
            log.info("Started Application in {} ms." , (System.currentTimeMillis() - startTime));
            // 保持服务器进程
            tomcat.getServer().await();
        } catch (Exception e) {
            log.error("Application startup failed...", e);
        }
    }
}

03、添加测试类

这个类的的静态方法run() 就是后边提供给引用框架的项目使用的,我们先创建一个测试类,启动一下试试

T.java

public class T {
    public static void main(String args[]){
        SquareApplication.run(T.class, args);
    }
}

运行结果:

信息: Starting ProtocolHandler ["http-nio-8080"]
10:24:36.776 [main] INFO com.jisuye.core.SquareApplication - Tomcat started on port(s): 8080 with context path '/'
10:24:36.778 [main] INFO com.jisuye.core.SquareApplication - Started Application in 2174 ms.

日志输出已经启动成功了,现在访问一下http://localhost:8080

1-1.png

04、添加启动参数设置

OK,接下来我们改造一下,把参数解析加一下,项目启动时添加的参数--server.port:8089 要对应到我们的tomcat容器启动的端口,添加一个参数解析工具:

ArgsToKVUtil.java

public class ArgsToKVUtil {
    public static Map<String, String> convert(String[] args){
        Map<String, String> map = new HashMap<String, String>(args.length);
        for (String arg : args) {
            String[] tmp = arg.split("=");
            if(tmp.length == 2){
                map.put(tmp[0], tmp[1]);
            }
        }
        return map;
    }
}

逻辑很简单,只是把程序启动的参数数组args给解析成键值对的形式,在SquareApplication.java里添加设置参数方法setArgs(),然后在run()方法里先调用一下,下边是完整代码:

SquareApplication.java

public class SquareApplication {
    private static final Logger log = LoggerFactory.getLogger(SquareApplication.class);
    private static Tomcat tomcat = null;
    private static String CONTEXT_PATH = "/";
    private static String ENCODING = "UTF-8";
    private static int TOMCAT_PORT = 8080;

    public static void run(Class clzz, String[] args) {
        try {
            // 初始化参数
            setArgs(args);
            String project_path = clzz.getResource("").getPath();
            project_path = project_path.substring(0, project_path.indexOf("classes"));
            long startTime = System.currentTimeMillis();
            tomcat = new Tomcat();
            // 设置Tomcat的工作目录:工程根目录/Tomcat
            tomcat.setBaseDir(project_path + "/Tomcat");
            tomcat.setPort(TOMCAT_PORT);
            tomcat.addWebapp(CONTEXT_PATH, project_path);
            // 执行这句才能支持JDNI查找
            tomcat.enableNaming();
            tomcat.getConnector().setURIEncoding(ENCODING);
            tomcat.start();
            log.info("Tomcat started on port(s): {} with context path '{}'", TOMCAT_PORT, CONTEXT_PATH);
            log.info("Started Application in {} ms." , (System.currentTimeMillis() - startTime));
            // 保持服务器进程
            tomcat.getServer().await();
        } catch (Exception e) {
            log.error("Application startup failed...", e);
        }
    }

    /**
     * 初始化参数
     * @param args
     */
    private static void setArgs(String[] args){
        Map<String, String> map = ArgsToKVUtil.convert(args);
        if(map.get("--server.port") != null){
            TOMCAT_PORT = Integer.parseInt(map.get("--server.port"));
        }
    }

}

T.main()方法添加启动参数--server.port=8089再次运行T.main() 查看日志输出:

信息: Starting ProtocolHandler ["http-nio-8089"]
10:38:55.618 [main] INFO com.jisuye.core.SquareApplication - Tomcat started on port(s): 8089 with context path '/'
10:38:55.620 [main] INFO com.jisuye.core.SquareApplication - Started Application in 2192 ms.

可以看到设置的参数已经生效了。

05、添加banner

好的,容器已经基本嵌入进来了,该有的差不多也有了,已经实现了足够的简陋,注意我造轮子的目的,不忘初心(方能翻车)。
我觉得springboot的启动banner很不错,我打算学(抄)习(袭)一下。
首先在resources目录下创建default-banner.txt 文件,写入banner内容
default-banner.txt:

 __________  ____
|   ____   |/ ___|  __ _ _   _  __ _ _ __ ___
|  |    |  |\___ \ / _` | | | |/ _` | '__/ _ \
|  |____|  | ___) | (_| | |_| | (_| | | |  __/
|__________||____/ \__, |\__,_|\__,_|_|  \___|
======================|_|====================
 :: Square ::        (v0.1)

在SquareApplication.java中添加输出banner方法:

/**
     * 输出banner图
     */
    private static void printBanner(String projectPath){
        BufferedReader br = null;
        try{
            File f = new File(projectPath + "/classes/default-banner.txt");
            br = new BufferedReader(new FileReader(f));
            StringBuilder stringBuilder = new StringBuilder("\n");
            String line;
            while ((line = br.readLine()) != null){
                stringBuilder.append(line).append("\n");
            }
            log.info(stringBuilder.toString());
        } catch (Exception e){
            log.info("load banner file error!!", e);
            if(br != null){
                try {
                    br.close();
                } catch (IOException e1) {
                }
            }
        }
    }

run() 方法中添加输出引用:

 public static void run(Class clzz, String[] args) {
        try {
            long startTime = System.currentTimeMillis();
            // 初始化参数
            setArgs(args);
            String project_path = clzz.getResource("").getPath();
            project_path = project_path.substring(0, project_path.indexOf("classes"));
            // ===========输出banner============
            printBanner(project_path);
            tomcat = new Tomcat();
            //....略,以下代码上边已有

最后我们来运行一下T.main()查看输出:

13:02:45.086 [main] INFO com.jisuye.core.SquareApplication - 
 __________  ____
|   ____   |/ ___|  __ _ _   _  __ _ _ __ ___
|  |    |  |\___ \ / _` | | | |/ _` | '__/ _ \
|  |____|  | ___) | (_| | |_| | (_| | | |  __/
|__________||____/ \__, |\__,_|\__,_|_|  \___|
======================|_|====================
 :: Square ::        (v0.1)

......
信息: Starting ProtocolHandler ["http-nio-8089"]
13:02:47.226 [main] INFO com.jisuye.core.SquareApplication - Tomcat started on port(s): 8089 with context path '/'
13:02:47.227 [main] INFO com.jisuye.core.SquareApplication - Started Application in 2144 ms.

添加完成!

06、翻车现场

上边的代码写完的时候我还没有意识到自己的问题,直到做在回家的车上才想起来,这么干得翻车啊。

把web目录设置在classes的上一级,也就是说classes是可以通过连接地址请求到的(像静态资源一样),试了一下果然是这样。这个问题下一篇再解决吧......

本篇代码地址: https://github.com/iuv/square

本文作者: ixx
本文链接: http://jianpage.com/2019/06/20/square1/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!

上一篇 下一篇

猜你喜欢

热点阅读