天下武功唯简不破,如何实现最简单的自启动?


天下武功唯简不破, 如何骑在驴身上然后牵着驴往前走?

热启动:
JFinal Undertow 热加载, 就属于热启动,改了代码自动加载生效。一般都需要自定义ClassLoader来实现。

冷启动:
手工点停止,开始按钮强行停止服务。从而触发默认ClassLoader重新加载。

除了热启动和冷启动其实还可以实现一种自启动 -> 自动调用冷启动, 来达到不用手工冷启的效果。

PS:这种不适合线上环境, 仅适用于本地开发环境, 提升开发体验和效率, 就像默认线上会关闭热加载一样.

/**
	 * 全程避免使用 super.loadClass(...),以免被 parent 加载到不该加载的类
	 */
	protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
		/**
		 * 生产环境所有类文件统一加载方式,不再进行额外判断
		 * 生产环境避免使用 parent 加载,是为了能从额外添加的
		 * config 目上录下面加载配置文件
		 */
		if (! UndertowConfig.isDevMode()) {


启动时把server 实例存起来

public static void main(String[] args) {
		// 启动Server全局共享
		UndertowUtil.server = UndertowServer.create(AppConfig.class).addSystemClassPrefix("com.eova.common.utils.util.UndertowUtil");
		UndertowUtil.server.addHotSwapClassPrefix("org.beetl.").addHotSwapClassPrefix("com.eova.").start();
	}

所以就可以实现静态的全局共享, 在启动时把UndertowServer对象存起来, 就可以随时拿出来按在地上磨 擦(restart).

public class UndertowUtil {

	/**
	 * 当前启动服务全局共享
	 */
	public static UndertowServer server = null;

	/**
	 * 重启当前服务
	 */
	public static void restart() {
		if (server != null) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						System.err.println("Undetow Server Restarting ......");
						Thread.sleep(500);// 延迟500ms, 避免Web来不及返回信息
						server.restart();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}).start();

			return;
		}
	}

关键的梗

.addSystemClassPrefix("com.eova.common.utils.util.UndertowUtil")

判断是否为系统类文件,系统类文件无条件使用 parent 类加载器加载


如果不添加为SystemClass 就会导致静态变量最终为null, 两个时空的类加载 静态变量分别初始化 无法共享

可以通过输出HashCode 发现不一样, 说明存在于不同的内存中.


ClassLoader 和 JVM 可以说是最Java最底层的东西了, 水很深, 需要慢慢修-炼-内-功.

https://blog.csdn.net/kdsde/article/details/81537024


评论区

JFinal

2020-08-11 16:00

addSystemClassPrefix 这个功能多年前就有了,今天总算被用上了,倍感欣慰

在需求未到来之前就能预知并实现功能,极端考验设计者的智慧

点赞

zhangtianxiao

2020-08-11 16:39

晚点试试, 能不重新创建jfinalConfig吗

杜福忠

2020-08-11 17:49

之前有用ServerSocket自建一个HTTP 服务然后提供了UndertowServer的restart服务,但是执行undertowServer.restart()老报错,然后一忙,又没有时间细看了。。。
看老师成功了,也就是说理论是可行的,我回头再细研究研究问题出哪里了。。
UndertowServer.jpg

杜福忠

2020-08-11 17:50

应该就是那个”关键的梗“的核代码了

海哥

2020-08-11 18:56

弱弱的问一下,这个的使用场景是啥?

李通

2020-08-11 21:05

@Jieven 重启undertow为什么要要新增一个线程

李通

2020-08-11 21:08

@杜福忠 start有些多余吧,怎么可能用到呢?

李通

2020-08-11 21:19

测试了,直接使用UndertowUtil.server.restart();失败

李通

2020-08-11 21:20

@海哥, 可以通过contrller重启undertow
```
public class UndertowController extends Controller {
public void restart() {
//UndertowUtil.server.restart();
UndertowUtil.restart();
renderText("OK");
}

public void stop() {
UndertowUtil.server.stop();
renderText("OK");
}

public void status() {
boolean started = UndertowUtil.server.isStarted();
renderJson(started);
}
}
```

杜福忠

2020-08-12 09:07

@李通 自己学习倒腾了,当时是想做一个 和Tomcat 管理项目的启动|关闭|重启 操作来着。。。后来一报错,没倒腾出来,然后一想这玩意作用不大,就没有继续研究了,放一边了。。。

Jieven

2020-08-12 10:15

@海哥 走捷径的热部署(仅限开发环境), 如果要做线上热部署, 就得像JPress那样自定义ClassLoader来 全生命周期 接管 Ctrl intercept Handler 这些, 没有海哥20年的功力, 一般人驾驭不了, 也太麻烦了.

Jieven

2020-08-12 10:20

@李通 那个线程就是为了让你看到成功的结果

Jieven

2020-08-12 10:36

@杜福忠 如果是做Tomcat那样的, 还是 cmd 去执行命令比较靠谱, 热加载线上不会开启, 这个方案就没用.