Pesquisa Tomcat vs Weblogic JNDI
Pergunta
Os servidores Weblogic que estamos usando foram configurados para permitir nomes de fontes de dados JNDI como "appds".
Para desenvolvimento (localhost), podemos estar executando o Tomcat e quando declarado na seção <context> do server.xml, o Tomcat irá travar fontes de dados JNDI em "java:comp/env/jdbc/*" na árvore JNDI.
Problema: no Weblogic, a pesquisa JNDI é "appds", enquanto no Tomcat, parece que devo fornecer o formal "java:comp/env/jdbc/appds".Receio que a versão do Tomcat seja um padrão implícito, mas infelizmente não posso alterar a configuração do Weblogic ...isso significa que teremos dois arquivos de configuração diferentes do Spring (estamos usando o Spring 2.5) para facilitar os diferentes ambientes.
Existe uma maneira elegante de resolver isso.Posso procurar nomes JNDI diretamente no Tomcat?A Primavera pode pegar um nome e procurar nos dois lugares?Pesquisas ou sugestões do Google seriam ótimas.
Solução
JndiLocatorSupport
tem uma propriedade resourceRef
.Ao definir isso como verdadeiro, o prefixo "java:comp/env/" será anexado automaticamente.Então acredito que seria correto diferenciar esse parâmetro ao passar do Tomcat para o Weblogic.
Outras dicas
Como usar um único nome JNDI em seu aplicativo web
Eu mesmo lutei com isso por alguns meses.A melhor solução é tornar seu aplicativo portátil para que você tenha o mesmo nome JNDI no Tomcat e no Weblogic.
Para fazer isso, você muda seu web.xml
e spring-beans.xml
para apontar para um único nome jndi e fornecer um mapeamento para cada nome jndi específico do fornecedor.
Coloquei cada arquivo abaixo.
Você precisa:
- A
<resource-ref />
entrada em web.xml para seu aplicativo usar um único nome - Um arquivo
WEB-INF/weblogic.xml
para mapear seu nome jndi para o recurso gerenciado pelo WebLogic - Um arquivo
META-INF/context.xml
para mapear seu nome jndi para o recurso gerenciado pelo Tomcat- Isso pode ser na instalação do Tomcat ou no seu aplicativo.
Como regra geral, prefira ter seus nomes jndi em seu aplicativo, como jdbc/MyDataSource
e jms/ConnFactory
e evite prefixá-los com java:comp/env/
.
Além disso, as fontes de dados e os connection factorys são melhor gerenciados pelo contêiner e usados com JNDI.É um erro comum ao instanciar pools de conexões de banco de dados em seu aplicativo.
primavera
<?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:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
<jee:jndi-lookup jndi-name="jdbc/appds"
id="dataSource" />
</beans>
web.xml
<resource-ref>
<description>My data source</description>
<res-ref-name>jdbc/appds</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
weblogic.xml
<?xml version="1.0" encoding="UTF-8" ?>
<weblogic-web-app
xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://xmlns.oracle.com/weblogic/weblogic-web-app http://http://www.oracle.com/technology/weblogic/weblogic-web-app/1.1/weblogic-web-app.xsd">
<resource-description>
<jndi-name>appds</jndi-name>
<res-ref-name>jdbc/appds</res-ref-name>
</resource-description>
</weblogic-web-app>
META-INF/context.xml (para Tomcat)
<Context>
<ResourceLink global="jdbc/appds" name="jdbc/appds" type="javax.sql.DataSource"/>
</Context>
Consegui fazer o truque com Tomcat e WebLogic usando Spring. Aqui é uma descrição de como funcionou para mim.
A configuração a seguir funciona no Tomcat e no Weblogic para mim.
Na primavera:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<!-- This will prepend 'java:comp/env/' for Tomcat, but still fall back to the short name for Weblogic -->
<property name="resourceRef" value="true" />
<property name="jndiName" value="jdbc/AgriShare" />
</bean>
No Weblogic Admin Console, crie um recurso JDBC chamado jdbc/AgriShare
.Em 'Metas', CERTIFIQUE-SE DE DIRECIONAR A FONTE DE DADOS PARA O SERVIDOR EM QUE ESTÁ IMPLEMENTANDO SEU APLICATIVO!.Este ponto em particular me custou algum tempo agora...
Que tal uma variável de ambiente?Defina as máquinas dos desenvolvedores com o nome tomcat e a produção com o nome Weblogic.Você pode até configurar seu código para usar um código padrão (WebLogic) caso a variável não exista.
Como você está referenciando o recurso na primavera?
Isto é o que temos para o Tomcat:
contexto:
<Resource name="jms/ConnectionFactory" auth="Container" type="org.apache.activemq.ActiveMQConnectionFactory" description="
JMS Connection Factory"
factory="org.apache.activemq.jndi.JNDIReferenceFactory" brokerURL="tcp://localhost:61615" brokerName="StandaloneAc
tiveMQBroker"/>
primavera:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<jee:jndi-lookup jndi-name="jms/ConnectionFactory" id="connectionFactory" resource-ref="true"
expected-type="javax.jms.ConnectionFactory" lookup-on-startup="false"/>
O namespace jee vem de:
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd
Configurar o DataSource no aplicativo em si não é tão maluco :) Eu diria que é até obrigatório se o aplicativo for implantado em uma grade.Rio, GigaSpaces ou similar.
Observação:Não digo que as configurações de conexão devam ser codificadas dentro do WAR, elas precisam ser fornecidas no tempo de implantação/tempo de execução.Isso simplifica o gerenciamento de instâncias de nuvem, pois só há local para configuração.
Configurar recursos no contêiner só faz sentido se vários aplicativos estiverem implantados lá e puderem usar recursos compartilhados.
Novamente, em implantações do tipo nuvem, há apenas um aplicativo por instância de contêiner de servlet.
Meu aplicativo também teve um problema semelhante e foi assim que resolvi:
1) WEB-INF/classes/application.properties
contém a entrada:
ds.jndi=java:comp/env/jdbc/tcds
2) Na máquina WLS, tenho uma entrada no /etc/sysenv
arquivo:
ds.jndi=wlsds
3) Configurei o spring para pesquisar o JNDI na propriedade ${ds.jndi}
, usando um PropertyPlaceholderConfigurer
feijão com classpath:application.properties
e file:/etc/sysenv
como locais.Eu também configurei o ignoreResourceNotFound
para true
para que os desenvolvedores não precisem ter /etc/sysenv
em suas máquinas.
4) Executei um teste de integração usando Cargo+Jetty e não consegui configurar corretamente um ambiente JNDI lá.Então eu tenho um substituto BasicDataSource
configurado também usando o defaultObject
propriedade de JndiObjectFactoryBean
.