造一个方形轮子文章目录:造一个方形的轮子
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

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 国际许可协议 进行许可。转载请注明出处!
网友评论