文章和随附的代码项目涉及的方法是克服WebSphere 8.5(WAS)应用程序容器中迁移到Spring 5和Spring Boot 2应用程序的障碍的方法。当Spring使用更新的验证罐时,出现问题,默认情况下使用父母的第一类加载策略,该策略将阻碍升级。
具体来说,提供了几个选项,以方式更改类加载程序以使用parent last。此外,我们在您的maven pom.xml中的示例JSP项目中召集了春季和春季启动所需的特定罐子。
预计,随着这些更改,您可以迁移到支持的春季版本,同时保持投资为8.5。直到这些产品达到生命的尽头。
默认情况下,WebSphere Application Server 8.5.x(WAS8)使用parent_first class Loader策略。通常,这意味着将首先加载其Application Server(EE)罐子的版本,并优先考虑您的分发中的内容。
例如,您可能在Web-Inf lib目录中具有验证API的一个版本,但是类路径将偏爱这是一个。有效地将您的版本带到阴影,以支持随附的JEE版本。这很有意义,IBM花了很多时间通过已知的Javax进行认证和测试其应用程序服务器。
当您想使用较新版本的Spring 5.X和Spring Boot 2.X时,擦拭就来了,这些版本正在使用并依靠较新版本的Javax valtidation和Hibernate验证来实现其核心功能。你做什么工作?
选项1是升级您的应用程序服务器。这是Apache Tomcat,Open Liberty,JBoss和许多其他开源实现的直接前进。这是因为一个巨大的挑战是。多年来,JDK 8.x的许多批判性和遗产应用程序一直在运行8.5,而且该业务几乎不希望为一些昂贵的回归测试付费。当然,春季4.x是生命的终结,但仍然有效,所以为什么要升级?最好的答案不是5.x更酷,它可以帮助我的简历。真正的答案是漏洞。您不再受到支持,这是一个问题,而不是在野外发现新的漏洞。您想领先于这种情况。
什么不是9?好吧,我把那个留给你。就个人而言,如果您远离8岁。除非您对自定义有所垂死,否则上述开源实现的功能是8功能。您可以在任何环境中的云中尽可能多地在想要的地方部署任意数量的地方。容器或本地。您的选择和首席财务官不在乎。
我们要在此处解决的选项只是将classlaader从父级转换为parth last。这不是长期解决方案。这只是让您进入春季的支持,您的业务可以为此“春季”。你得到它的“春天”,我很痛。这也不是银弹。我相信您的基础设施团队已经投资了脚本,并且在稳定的群集中拥有良好的跑步节点。使用父级部署新节点可能会影响其他不迁移但在同一单元格中的应用程序。你在那里做什么?
有很多方法可以完成这项任务。我们不会深入研究这些细节。我会给您三(3)个高级解决方案,让您选择。
这是最危险和最不记录的。在这里,您可以使用特定于IBM的注释来更新耳朵中的一些晦涩的XML文件,并希望获得最好的XML文件。好处是您不需要更改脚本。缺点?我无法在生产环境中证明这项工作。以下是有关该主题的一些堆栈溢出文章。买家当心
这是在WAS的开发人员版本中使用的,或者如果您可以访问IS管理控制台。此选项是证明您的更改的好方法。当然,主要的问题是这些变化是不可扩展的,也无法脚本脚本。您可能会喜欢此选项,但是您的基础架构团队不太可能会在每个模块部署后都会愉快地更新您的耳朵。这不是一个可观的选择。
这确实是您唯一的生产选择。您将需要与基础架构团队并驾齐驱,以更新其部署脚本,以在部署期间和启动应用程序之前更改ClassLoader。我包括了一个示例开发人员(未经过高度测试)Jython(PY)文件,以使您的合作伙伴指出。
您可以从这里看到我的jython脚本的灵感
print ( "Get Deployments : " )
deployments = AdminConfig . getid ( '/Deployment:' + APP_NAME + '/' )
print deployments
print ( "" )
print ( "Deployment Object" )
deploymentObject = AdminConfig . showAttribute ( deployments , 'deployedObject' )
print deploymentObject
myModules = AdminConfig . showAttribute ( deploymentObject , 'modules' )
myModules = myModules [ 1 : len ( myModules ) - 1 ]. split ( " " )
print myModules
for module in myModules :
if ( module . find ( 'WebModuleDeployment' ) != - 1 ):
AdminConfig . modify ( module , [[ 'classloaderMode' , 'PARENT_LAST' ]])
AdminConfig . save ()
print ( "Set module to PARENT_LAST" )这种变化完全在您身上。您将需要开发人员服务器或本地服务器来查看和验证更改,但是您需要使用特定更改进行验证和休眠状态更新pom.xml 。
第一次部署后,更改类加载程序后,您将在Systemout日志中看到以下错误:
引起:java.lang.classnotfoundexception:javax.validation.parameternameprovider
Spring 5.x依赖于有效TAPI的2.x版本,因此您需要明确升级POM中的API。同样,这是可能的,因为您更改了类加载程序。没有这种变化,您就会从WAS类路径上加载1.x版本。没有工作。如果您使用JSP页面,还有其他更改。请参阅WAS8-WAR项目中的pom.xml。
特别说明,如果您使用的是瓷砖2.x,则需要升级到瓷砖3.x。那将是另一个帖子。
< dependency >
< groupId >javax.validation</ groupId >
< artifactId >validation-api</ artifactId >
< version >2.0.1.Final</ version >
</ dependency >虽然不是具体的,但我们需要包括tomcat-embed-jasper依赖性,以允许我们的应用程序编译并渲染JSP页面以进行本地运行。不是设置为提供的范围
< dependency >
< groupId >org.apache.tomcat.embed</ groupId >
< artifactId >tomcat-embed-jasper</ artifactId >
< version >${tomcat-embed-jasper.version}</ version >
< scope >provided</ scope >
</ dependency >有关所需的其他罐子,请参见Spring Boot 2.x Readme.md。
如果您走了这么远,则使用Java配置。忘记旧样式的XML配置。那是如此的春天4.x。你比现在更好。
请注意JSP页面的位置: /Web-Inf/views/
@ Configuration
@ EnableWebMvc
@ ComponentScan ( basePackages = { "org.scavino" })
public class AppConfig {
/**
* ViewResolver allows setting properties such as
* prefix (/WEB-INF/views/) or suffix (*.jsp) to the view name to generate
* the final view page URL. In our case this is how
* we will configure JSP pages.
*
* @return JSP resolver with prefix set to /WEB-INF/views/
*/
@ Bean
public InternalResourceViewResolver resolver () {
InternalResourceViewResolver resolver = new InternalResourceViewResolver ();
resolver . setPrefix ( "/WEB-INF/views/" );
resolver . setSuffix ( ".jsp" );
return resolver ;
}
}我们正在扩展AbstractAnnotationConfigDisPatcherServletInialializer以访问密钥配置。为什么?我们可以使用Spring提供的便利类,而不是手动配置DispatcherServlet和/或ContextLoaderListener
public class SpringMvcDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@ Override
protected Class <?> [] getRootConfigClasses () {
return null ;
}
@ Override
protected Class <?> [] getServletConfigClasses () {
return new Class [] {
AppConfig . class
};
}
@ Override
protected String [] getServletMappings () {
return new String [] {
"/"
};
}