Artigo e código de código que acompanha o método que supera os obstáculos que migram para os aplicativos Spring 5 e Spring Boot 2 em um contêiner do aplicativo WebSphere 8.5 (WAS). Os problemas surgem à medida que a primavera está usando frascos de validação atualizados e, por padrão, usavam uma estratégia de carregamento de primeira classe pai que atrapalharia uma atualização.
Especificamente, várias opções são apresentadas sobre como alterar o carregador de classe para usar o pai por último. Além disso, chamamos os frascos específicos necessários para a bota de primavera e primavera em um projeto JSP de amostra no seu maven pom.xml.
Espera -se, com essas alterações, você pode migrar para uma versão suportada da primavera, mantendo seu investimento em 8,5. Isso é até que esses produtos atinjam o fim da vida.
Por padrão, o WebSphere Application Server 8.5.x (WAS8) usa a estratégia de carregador de classe parent_first. Em geral, esse meio foi carregar sua versão dos frascos de servidor de aplicativos (EE) primeiro e se priorizar sobre o que está em sua distribuição.
Por exemplo, você pode ter uma versão da API de validação no seu diretório Web-Inf lib, mas o caminho da classe favorecerá o primeiro. Efetivamente, sombreando sua versão em favor da versão JEE que veio. Isso faz sentido, a IBM gastou muito tempo certificando e testando seu servidor de aplicativos com um conjunto conhecido de Javax.* Jars e deseja mantê -lo dessa maneira por padrão.
O Rub vem quando você deseja usar uma versão mais recente do Spring 5.x e a Spring Boot 2.x e essas versões estão usando e confiar em uma versão mais recente da Valtidação Javax e Validação de Hibernato para sua funcionalidade principal. O que você faz?
A opção 1 é atualizar seu servidor de aplicativos. Isso é bastante direto com o Apache Tomcat, Open Liberty, JBoss e muitas outras implementações de código aberto. Isso porque um grande desafio com foi. Muitos aplicativos críticos e legados estão em execução foi de 8,5 com o JDK 8.x por anos, e os negócios têm pouco desejo de pagar por alguns testes de regressão caros. Claro que a primavera 4.x é o fim da vida, mas ainda funciona, então por que atualizar? A melhor resposta não é que o 5.x seja mais legal e que ajuda meu retomar. A resposta real são vulnerabilidades. Você não é mais suportado e isso é um problema quando, não se, novas vulnerabilidades forem encontradas na natureza. Você quer ficar à frente desse cenário.
O que não foi 9? Bem, eu deixo isso para você. Pessoalmente, se você estiver migrando para longe de 8 anos. A menos que você tenha alguma necessidade de morrer de costume, foi a funcionalidade de 8, as implementações de código aberto acima se sairão bem. Você pode implantar quantos quiser em quantos lugares quiser em qualquer ambiente, nuvem. contêiner ou no local. Sua escolha e seu CFO não se importam.
A opção que vamos abordar aqui é apenas alternar o carregador de classe do pai primeiro para o pai anterior. Esta não é uma solução de longo prazo. Isso apenas leva você ao apoio da primavera e sua empresa pode "primavera" para essas mudanças. Você entendeu "primavera", estou sendo insignificante. Além disso, isso não é uma bala de prata. Tenho certeza de que suas equipes de infraestrutura investiram em seus scripts e têm nós de execução bem em clusters estáveis. A implantação de um novo nó com os pais passou por último pode afetar outro aplicativo que não está migrando, mas está na mesma célula. O que você faz lá?
Existem muitas maneiras de realizar essa tarefa. Não vamos nos aprofundar nesses detalhes. Vou lhe dar três (3) soluções de alto nível e deixar você escolher.
Este é o mais arriscado e menos documentado. Aqui você atualiza algum arquivo XML obscuro em seu ouvido com anotações específicas da IBM e espera o melhor. A vantagem é que você não precisa alterar seus scripts. A desvantagem? Não consegui provar que isso funciona em ambientes de produção. Abaixo estão alguns artigos de transbordamento de pilha sobre o assunto. Comprador, cuidado
Este funciona e funciona muito bem com as versões do desenvolvedor de WAS ou se você tiver acesso ao console administrativo. Esta opção é uma ótima maneira de provar suas mudanças. O principal problema, é claro, é que essas mudanças não são escaláveis nem podem ser roteirizadas. Você pode gostar dessa opção, mas é improvável que suas equipes de infraestrutura atualizem com prazer seu ouvido após cada implantação de módulos. Esta não é uma opção scable.
Esta é realmente sua única opção para produção. Você precisará trabalhar de mãos dadas com suas equipes de infraestrutura para atualizar os scripts de implantação para alterar o carregador de classe durante a implantação e antes de iniciar o aplicativo. Incluí um arquivo Jython (PY) de um desenvolvedor de amostra (o que significa altamente testado) para levar o ponto aos seus parceiros.
Você pode ver minha inspiração para o script Jython daqui
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" )Essa mudança é totalmente sobre você. Você precisará de um servidor de desenvolvedor ou servidor local para ver e validar suas alterações, mas precisará atualizar seu POM.xml com alterações específicas para validação e hiberna.
Após o seu primeiro, você implanta e, depois de alterar o carregador de classe, você verá o erro abaixo nos logs do Systemout:
Causado por: java.lang.classnotfoundException: javax.validation.parameternameProvider
Spring 5.x depende da versão 2.x do API válido , portanto, você precisará atualizar explicitamente a API em seu POM. Novamente, isso só é possível porque você mudou o carregador de classe. Sem essa alteração, você está preso na versão 1.x de carregamento do caminho da classe. Não há trabalho de trabalho. Existem outras alterações se você estiver usando páginas JSP. Veja o Pom.xml no projeto WAS8-WAR.
NOTA ESPECIAL Se você estiver usando ladrilhos 2.x, precisará atualizar para os ladrilhos 3.x. Esse será outro post.
< dependency >
< groupId >javax.validation</ groupId >
< artifactId >validation-api</ artifactId >
< version >2.0.1.Final</ version >
</ dependency >Embora não tenha sido específico, precisamos incluir a dependência do Tomcat-Jasper para permitir que nosso aplicativo compile e renderize páginas JSP para corrida local. Não o escopo está definido como fornecido
< dependency >
< groupId >org.apache.tomcat.embed</ groupId >
< artifactId >tomcat-embed-jasper</ artifactId >
< version >${tomcat-embed-jasper.version}</ version >
< scope >provided</ scope >
</ dependency >Consulte a bota da primavera 2.x README.MD para obter os frascos adicionais necessários.
Você está usando o Java Config se já foi até aqui. Esqueça a configuração XML do estilo antigo. Isso foi tão primavera 4.x. Você é melhor do que isso agora.
Observe o local para as páginas 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 ;
}
}Estamos estendendo o abstratoNotationConfigDispatcherSertLeTIlitializer para ter acesso à configuração de chave. Por que? Podemos usar as classes de conveniência fornecidas pela primavera em vez de configurar manualmente o DispatcheserServlet e/ou o 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 [] {
"/"
};
}