21.Spring Bean及Java类的热部署
简介
从2.1.1版本开始,在URule Pro中提供了Spring Bean及Java类的热部署功能。利用该功能,打开URule Pro控制台即可将需要热部署的Spring Bean及相关Java类文件实时部署到正在运行的服务器中。 对于采用客户端服务器模式运行的URule Pro应用,只需要在服务端部署好需要的Spring Bean及相关Java类文件,客户端会自动获取这些已部署的Spring Bean及相关Java类文件信息,并对其进行执加载。
有了这个功能,URule Pro中无论是用户自定义的动作库还是内置动作库相关的Spring Bean及Java类,都可以在服务器运行情况下,实时动态部署。
部署方式
打开URule Pro控制台,点击左侧项目列表上方按钮,即可打开动态部署Jar文件的配置页面,如下图所示:
在上面的部署页面中,可以点击“添加”按钮添加一个新的部署项,接下来点击具体部署项“操作”列中的“编辑”按钮,即可在弹出的窗口中添加这个部署项中涉及到的Jar文件信息,如下图所示:
在这个弹出的窗口中,可以把所有相关的Jar文件通过窗口里选择文件按钮上传到知识库中,完成之后点击页面工具栏上“部署”,即可将所有部署项中上传的Jar文件动态部署到当前项目中;如果当前项目被当前URule Server使用,同时又在各个项目里配置了URule的客户端地址, 那么在Server上部署完成后,系统会提示我们要不要将这些动态的Jar文件推送到URule客户端,如果选择是,那么这些客户端立即接收到这些Jar文件并动态加载,如下图所示:
在URule Server的规则项目里配置客户端地址,可以参见客户端服务器配置介绍,这里不再赘述。
Spring配置文件及Jar文件要求
从部署方式上了解到,我们只需要将需要热部署的Jar包上传到系统即可,如果其中要加载Spring Bean,那么还需要定义好Spring的xml配置文件放在Jar包中一并上传,下面来举例说明Spring配置文件及Jar文件打包方式。
假如我们需要部署下面这个Java类文件,内容如下:
package test;
/**
* @author Jacky.gao
* @since 2019年1月11日
*/
public class BusinessTest {
public String hello(String name) {
System.out.println(new OtherBusiness().getENV());
return "Hello, "+name;
}
}
从上面的代码中可以看出,这里的hello方法引用了OtherBusiness类中的getENV方法,OtherBusiness类源码如下:
package test;
/**
* @author Jacky.gao
* @since 2019年1月11日
*/
public class OtherBusiness {
public String getENV() {
return "环境 is OK...";
}
}
可以看到getENV方法非常简单,只是返回一个字符串而已,对于BusinessTest类,我们希望它成为一个标准的Spring Bean,所以还要添加一个Spring的xml配置文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<bean id="dybean" class="test.BusinessTest"></bean>
</beans>
在上面这段xml配置中,test.BusinessTest类被配置成为一个标准的Spring Bean,Bean的ID为dybean。到这里Java类的编写及Spring Bean的xml配置工作就完成了,接下来就需要将它们打包Jar并上传到URule中实际热部署。
为了演示Java类引用多个不同Jar包中其它类库的情形,这里我们把BusinessTest类和OtherBusiness类打成两个Jar文件,分别是main.jar和slave.jar,至于Spring Bean的xml配置文件放在两个Jar文件中任何一个中都可以,只是xml的名称必须是urule-spring-context.xml, 且这个名为urule-spring-context.xml的Spring配置文件必须放在Jar文件的根下,这里我们把这个urule-spring-context.xml文件打包在main.jar文件当中。
打包好的main.jar文件结构如下图所示:
打包好的slave.jar文件结构如下图所示:
上面的两个Jar文件中,BusinessTest类和OtherBusiness类都位于test这个package下,所以截图中只看到test这个package。 对于URule Pro来说,每个Jar文件中都可以包含一个名为urule-spring-context.xml的Spring的xml配置文件,如果包含每个文件中的Spring配置文件都会被解析并加载; 当然也可以都不包含,这样热部署时引擎只会加载Jar包中的类。
配置
当我们点击“态部署Jar文件的配置页面”上的部署按钮时,系统会尝试取到知识库里所有已上传的Jar文件,然后通过System.getProperty("java.io.tmpdir")取到当前JVM应用的临时目录,同时在其下创建名为urule-jars的目录, 最后取当前系统日期作为Jar文件的最终存储目录。
每次点击“部署”按钮时,系统都会尝试删除原来的由系统日期生成的子目录,再根据当前日期重新创建子目录,再把所有的Jar文件放在这个目录下。
在临时目录中生成好所有的已上传的Jar文件后,接下来系统会尝试加载这个目录下的所有Jar文件,如果这些Jar文件根下包含名为urule-spring-context.xml的Spring配置文件,系统也会将这个文件加载到Spring上下文中。 在实际使用时,如果运行URule Pro的应用采用集群部署,并且集群实例运行在同一个JDK下,这样多个实例运行时通过System.getProperty("java.io.tmpdir")取到当前JVM应用采用的临时目录可能是同一个目录,不同的实例操作同一个目录可能会存在问题, 为解决这种因集群而导致的问题,URule Pro允许为每个实例设置一个名为urule.instance.id的JVM参数,要保证每个实例下该参数值不同, URule Pro在启动时就会尝试采用这个JVM参数值作为通过System.getProperty("java.io.tmpdir")取到当前临时目录下的子目录名称,这样每个实例只会在这个子目录下进行创建存储Jar文件的目录,通过这种方式就可以避免在一台物理机器上搭建多集群实例 而产生的问题。
实际使用中,如果我们不想让引擎通过System.getProperty("java.io.tmpdir")这种方式,取到的临时目录来作为动态Jar文件的存储父目录,那么可以在Spring的Properties文件中添加一个名为urule.dynamicJarsPath的属性来手工指定一个用于存储动态Jar文件的 父目录,需要注意的是通过urule.dynamicJarsPath属性指定的目录一定要存在,否则启动时会产生错误。
对于采用客户端服务器模式运行的应用来说,如果客户端是一个Java Web应用,那么只需要按照客户端服务器配置中介绍的在客户端中配置好接收服务端推送过来的知识库的Servlet即可,这样服务端动态Jar部署时会提示 是否推送到客户端,如果选是,那么这些动态Jar文件会直接推送到目标客户端,客户端收到后也会按照上述方式加载这些Jar文件及其中可能存在的名为urule-spring-context.xml的Spring配置文件。
和知识包的客户端一样,客户端也可以主动检查服务端是否存在动态Jar文件,检查方式也是在客户端上配置“urule.resporityServerUrl”属性值,所以从2.1.1版本开始,客户端中配置好“urule.resporityServerUrl”属性值后,客户端应用除了会利用这个URL到服务端下载规则包, 还会在启动时利用这个URL检查服务端是否存在动态加载的Jar文件,如果有则下载到客户端并加载;这时服务端的“urule/dynamic/checkLatestJarsDir”和“urule/dynamic/loadDynamicJars”这两个URL要保证匿名可访问,否则客户端启动时会产生错误。
如果客户端是一个标准的Java应用,而非一个Java Web应用,对于这种类型的应用来说,为了可以取到服务端生成的动态Jar文件,我们可以在客户端Spring的Properties文件中添加一个名为urule.dynamicJarsRemoteLoadInterval的属性 来决定客户端每隔多久利用客户端上配置的urule.resporityServerUrl属性值到服务端检查有没有新的动态Jar产生,如果有则从服务端取回并加载。
urule.dynamicJarsRemoteLoadInterval的属性值单位为分钟,如果我们设置其值为5,那就表示每隔5分钟到服务端检查是否生成新的动态Jar文件,如果不设置则表示客户端不会定期检查服务端是否有新的动态Jar包产生。