因项目部署环境改变成国产化环境,需要使用金蝶中间件,spring cloud的每个Project 可以直接打成jar包运行,里面自带了tomcat容器,所以要对spring cloud各个微服务模块进行改造。本文根据现有的项目架构,记录了怎么用最小的改动去完成适配,并且介绍怎么使用Apusic,来保持Euraka注册发现与负载均衡、服务的管理,保持原有的高可用。(本文只记录Linux下Apusic安装部署过程)
项目war包适配改造
下面是本文需要适配的spring cloud项目目录结构,因业务需要模块划分比较详细。
图一:项目工程目录.png
图二:子模块目录结构.png
下面是对项目的详细改造:
-
步骤一
为防止spring cloud内置的servlet container(tomcat),在发布war中不会与Apusic金蝶中间件冲突,需要标记内置tomcat依赖为provided,把内嵌的tomcat去掉。下面是两种移除方式,我使用的第二种方式。
方式一
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 移除嵌入式tomcat插件 -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
方式二
<!-- 移除嵌入式tomcat插件 -->
<!--provided:编译和测试时有效,但是该依赖在运行时由服务器提供,并且打包时也不会被包含进去-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
-
步骤二
为防止运行时,与金蝶中间件本身自带了servlet-api.jar包发生冲突,所以打包阶段移除了servlet-api
<!--打包的时候可以不用包进去,由是Apusic会提供。事实上该依赖理论上可以参与编译,测试,运行等周期。
相当于compile,但是打包阶段做了exclude操作-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
-
提醒:在上线测试中,本项目有个模块打成
war包后,存在移除了servlet-api会报错的情况,后来加上去就能正常运行,也不跟Apusic冲突,所以各位根据自己项目情况适当调整吧,也懒得去探究了 -
说明 :因本项目中所有子项目会依赖于父的
pom.xml文件,所以我们只需要在父pom.xml中加入排除内置的tomcat 、servlet-api依赖即可,也可以在子项目总pom.xml中添加(如图二web下的pom),每个模块都要改,这种方式比较麻烦不推荐。
步骤三
我的项目模块比较多,所以就比较麻烦了,需要在每个模块启动类下的pom.xml中添加<packaging>war</packaging>,修改打包类型,将默认的jar方式改为war
图三:web模块目录.png
图四:web模块pom文件.png
-
步骤四
修改启动类,并重写初始化方法
public class WebApplication extends SpringBootServletInitializer {
1、修改启动类,继承 SpringBootServletInitializer 并重写 configure 方法
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
System.out.println("======WebApplication====start==========");
return builder.sources(new Class[]{WebApplication.class});
}
2、由于Spring boot默认使用Tomcat作为嵌入式Servlet容器,来启动SpringBoot的web应用,所以需要修改servlet容器的配置
@Bean
public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
return new ServletRegistrationBean(dispatcherServlet, "/*");
}
3、如果模块需要上传文件需要添加下面的代码,如果没有可以忽略
@Bean(name = "multipartResolver")
public MultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setDefaultEncoding("UTF-8");
resolver.setResolveLazily(true);//resolveLazily属性启用是为了推迟文件解析,以在在UploadAction中捕获文件大小异常
resolver.setMaxInMemorySize(40960);
resolver.setMaxUploadSize(50 * 1024 * 1024);//上传文件大小 50M 50*1024*1024
return resolver;
}
}
需要上传文件的的服务,在加了上面代码3的配置后,还需要添加一个依赖包,不然,没这个包访问的时候会报错,找不到一个类
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
-
步骤五
在每个模块的application.properties中添加spring.jmx.default-domain=唯一名称,否则无法在金蝶中间件中启动,原因:spring.jmx是默认打开的每个jmx名字必须是唯一的!!,详细原因自己去查吧,照着做就行,如图五,我是用的服务注册标识,与注册到注册中心服务名保持一致,你也可以随意指定别重复就行,两者没啥关系。
spring.jmx.default-domain=service-web
图五web模块的配置.png
- 提示:金蝶中间件的某些版本存在了一个问题,如果你日志设置的info级别,启动后,控制台会疯狂刷屏,只能error才不刷屏。后来是换了版本,这个问题才好。
ok,到这儿基本的代码改动就算完成了,可以打war包了,剩下就是在发版到金蝶中间件中会遇到各种乱七八糟的问题了。
安装金蝶
金蝶版本AAS-V9.0,金蝶中间件需要jdk环境,所以需要先安装jdk,jdk版本应同时高于金蝶、iServer要求的版本。本文使用的金蝶要求jdk1.6及以上、iServer 8.1.1要求jre1.8及以上,所以这里使用JDK1.8(64位)。 解压 AAS-V9.0.zip文件即可,本文解压到以下目录/data/Apusic,解压缩即完成安装。license.xml为授权文件,必须有才能Apusic使用,window详细安装步骤,可参考金蝶用户手册。
图六金蝶解压后目录.png
下面介绍时,用
APUSIC_HOME描述Apusic服务器的安装目录路径,即本文解压后的/data/Apusic安装路径。
在
APUSIC_HOME路径下,有个domains,此文件内是所有服务的所在,APUSIC_HOME/domains目录下的 samples 内预部署了若干个示例应用,用以演示 JavaEE5 的新技术、新特性。samples 目录结构与 mydomain基本一致,存放示例应用的源代码及构建脚本。前段话是从用户手册上拷贝过来的,这些都不重要,我们主要用到的就是mydomain,这个目录,稍后再讲。
金蝶中间件可以允许在一个
domain中运行多个war包,这样的话,就会出现多个服务一个端口的问题(金蝶中间件的默认端口为6888),并且会为每个服务默认一个上下文根路径为"/服务名",比如访问我部署的web服务的接口地址就为:http://ip:6888/web,这样的情况我们在使用feignclient进行服务之间调用时,就会访问不到,feignclient就会废了,正常我们访问注册中心的web服务地址应该为:http://ip:自定端口,不会后缀服务名。
为了是实现
feignclient正常使用就必须对domain内服务进行拆分,实现一个服务一个domain,这就是APUSIC_HOME/domains目录中包含s意义啦。开始干
步骤一
拷贝mydomain 整个文件夹,改为自己的服务名称,mydomain 内部的default文件可以删除了,没啥用,sample觉得碍眼也可删除,以下都以我自己的web服务介绍。
cp -r mydomain 自己的服务名称(如图七)
图七:APUSIC_HOME/domains下多个模块服务.png
步骤二
选择
web服务目录进入,有四个重要目录需要关注,其他的不用管
| 目录 | 作用 |
|---|---|
| applications | war包服务放置目录 |
| bin | 服务启动脚本 |
| config | 服务配置目录,主要修改server.xml、apusic.conf这两个文件 |
| logs | 控制台日志输出 |
图八进入web服务内目录结构.png
1、 选择config目录进入,修改server.xml、apusic.conf配置文件
1.1、 修改server.xml,name为服务名称,base为applications目录下war包名称,如applications/web.war,修改后保存并退出。
vim server.xml
图九server.xml配置.png
1.2、 修改
apusic.conf配置文件,查找Port设置端口号,注意此处的端口必须与服务在Euraka注册中心的端口号保持一致,不然服务之间无法使用feignclient访问,修改后保存并退出。
vim apusic.conf
图十apusic.conf配置.png
- 注意 :服务部署到
apusic中间件启动后,各个服务模块会根据自生properties中配置的端口,注册到Euraka中,服务之间调用地址都是从Euraka获取到的,所以在给每个domain设置的端口要与注册到Euraka中保持一致,不然是无法访问的。
2、 在bin子目录中,提供了预设的启动脚本 startapusic,可直接使用此脚本启动 apusic 应用服务器。startapusic提供了多种启动参数,还可以配置 JVM 参数。修改startapusic启动脚本,在这个脚本中可以设置spring一些启动参数
图十一 bin文件内目录.png
本项目设置的启动使用
application-gmprd.properties配置文件,只需要修改else中即可,修改完成保存并退出。
vim startapusic
图十二 startapusic.png
启动脚本有两种方式:
终端退出,服务会关闭
第一种:./startapusic
后台启动方式下,终端的退出不会导致 apusic 服务的退出
第一种:nohup ./startapusic &
步骤三
最后一步,也是最重要的一步,为防止金蝶中间件在服务启动后,会指定http访问该应用时的上下文根路径(context-root)(以服务名即上下文根路径,前面讲到过),需要手动配置服务上下文根路径。根据金蝶用户手册29.2.2章节提供的方式,需要手动创建一个apusic-application.xml文件,使服务可以找到这个文件,以下是我总结了做出两种方式。
1、在server.xml中增加一个config配置项,指定 apusic-application.xml配置文件路径,如图十三,我把文件放在domains下,这样在需要部署多个服务是都可以指向这个一个文件,可以共用。
图十三server.xml中增加config配置.png
2、 把
apusic-application.xml文件放入打好的war包中,直接用解压工具打开war包,把文件拖入 META-INF 目录下,如下图十四:
图十四 war内的apusic-application文件
apusic-application.xml配置内容,直接复制可用
<!DOCTYPE apusic-application PUBLIC '-//Apusic//DTD Apusic Application 4.0//EN' 'http://www.apusic.com/dtds/apusic-application_4_0.dtd'>
<apusic-application>
<module uri="">
<web>
<context-root>/</context-root>
</web>
</module>
</apusic-application>
- 友情提示 :最好还是选用第二种方式,因为在使用第一种方式时,虽然解决了上下文根路径问题,但是
Apusic控制台会报错,apusic-application.xml是不合法的java文件,看着贼不舒服,不知道是Apusic问题还是什么,所以我选用的第二种方式,虽然每次打包,都要往META-INF拖入一遍,但是胜在不报错啊。噢,对了,如果用的第二中方式,就不要在配置config项了,不然还是有路径问题,都是一步步被坑过来的。
ok,到这里基本上所有的配置说明都讲解完事了,上传war到applications中,然后运行启动脚本,如图十五,看到Context Root [/]内没有服务名,就是设置成功了,可以部署你的多个服务测试下feignclient之间调用了。
图十五 启动日志.png
这种适配网上资料很少,希望能给你提供帮助!
金蝶还有个Web应用服务器监控管理平台,就不多介绍了,金蝶用户手册有介绍。
image.png
========================2020-7-7===============================
适配过程中又发现新问题:
弄了个注册中心,启动报错,这个包在tomcat下是没有问题的可以正常启动不报错,但是在金蝶中间件内启动就有问题了,Tomcat对不适用的类,不会进行加载,但是金蝶的会启动时候全局加载,导致对引用的代码比较严格。
org.apache.log.
根据报错问题排查,发现freemarker这个jar包内依赖org.apache.log.Hierarchy,但是在jar内并没有找到,如下图可以发现,无法找到,但是并不影响编译,最后解决方式是,引入org.apache.log解决:
image.png
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>compile</scope>
</dependency>
注意log4j的scope为<scope>compile</scope>
使用springboot的应用出现streamclose异常时,在vm.options加上这个参数apusic.webcontainer.close.after.forward=false,屏蔽streamclose异常,显示真实错误信息
在domains/mydomain/config/vm.options里面修改下
========================2020-10-27===============================
因为在 Apusic 应用服务器中部署的 Web 应用,提供多种策略指定 http 访问该应用时的上下文根路径(context-root)。
• 第一种:使用apusic-application.xml
参考 Apusic 的 default 应用的 apusic-application.xml 如下:
<!DOCTYPE apusic-application PUBLIC '-//Apusic//DTD Apusic Application 4.0//EN'
'http://www.apusic.com/dtds/apusic-application_4_0.dtd'>
<apusic-application>
<module uri="">
<web>
<context-root>/</context-root>
</web>
</module>
</apusic-application>
其中,<context-root>指定了该应用的上下文根路径为"/",即可使用 http://<hostname/访问该应用。 放在 war 包的 META-INF 目录,此目录与 WEB-INF 目录同级,并将 apusic -application.xml 文件放置在其中,即可生效。
• 第二种:base-context
在domain目录下 config 目录中的 server.xml 文件中,可指定一个应用的 base-context,如下:
<application name="default" base="applications/服务名" base-context="/" start="auto"/>
这种方式 服务启动报错的话,base-context可能会被自动去掉,也是很麻烦。所以我一直采用的第一种。
当 base-context 不为空时,如果应用没有配置 context-root,那么 base-context 即为该应用的 cont ext-root;如果该应用的 web 模块配置了 context-root,那么该应用所有 web 模块的 context-root 会以 b ase-context 为前缀。比如 app1 的 base-context 为 app1,app1 下有个 web 模块的 context-root 为 web1, 那么访问该 web 模块的路径为 http://hostname/app1/web1/。
• 应用名即上下文根路径
如果 base-context 和 context-root 都未配置,那么 apusic 会按照以下规则指定 web 应用的上下文 根路径:如果应用是ear模块,那么指定apusic-application.xml中该web module的uri值为根路径; 如果应用是 web 模块,那么 web 应用的根路径为 server.xml 中指定的应用名,即"name"属性的值。 如果上述值以".war"结尾,那么去除".war"后的值为 context-root。
第一种方式,因为部署的地方增多,每次都要手动放置apusic-application.xml很麻烦,所以做了调整,把apusic-application.xml放置在resource中
image.png
然后早pom.xml增加这个配置:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webResources>
<resource>
<directory>
src/main/resources
</directory>
<targetPath>
META-INF/
</targetPath>
<includes>
<include>**/apusic-application.xml</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
这样打包出来的war就自动带有apusic-application.xml配置了
image.png
- 提示错误
Caused by: java.lang.NoClassDefFoundError: org/apache/catalina/servlet4preview/http/HttpServletRequest
或
Caused by: java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]] - 错误原因
导错包了,HttpServletRequest类引入的包应该是javax.servlet.http.HttpServletRequest,而不应该是org.apache.catalina.servlet4preview.http.HttpServletRequest













网友评论