文章和隨附的代碼項目涉及的方法是克服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 [] {
"/"
};
}