Java Spring Tomcat: 自定义数据源工厂被忽略
Java Spring Tomcat: Custom DataSource Factory Being Ignored
我正在做一个需要在 运行 时间解析数据库密码的项目。我通过在 Tomcat 配置中指定 DataSourceFactory
来有效地在本地执行此操作。此过程可防止将任何凭据存储在纯文本配置文件中,并为我们提供自定义控件以在 运行 时间解析密码。我在本地取得了巨大的成功,但是当我将我的解决方案移动到 AWS 上的 real/non-embedded Tomcat 实例时,我看到了这个错误:
Could not invoke the static newInstance method on the named factory
class "org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory".
首先,围绕此错误消息有一些可疑的细节。第一(正如您将在下面看到的),尽管其他凭据有效(例如用户名、密码等),但我的工厂 class 在 tomcat 配置文件中被忽略了。
我的 DataSourceFactory
的代码需要引用 class 来解析一个值。
这是我为 tomcat:
配置的 xml
<?xml version='1.0' encoding='UTF-8'?>
<Context useHttpOnly="false">
<Resource auth="Container" name="mail/Session" type="javax.mail.Session"/>
<Resource name="jdbc/jndi"
auth="Container"
scope="Shareable"
type="javax.sql.DataSource"
useLocalSessionState="true"
cacheServerConfiguration="true"
useServerPrepStmts="true"
cachePrepStmts="true"
cacheCallableStmts="true"
elideSetAutoCommits="true"
alwaysSendSetIsolation="false"
enableQueryTimeouts="false"
prepStmtCacheSize="250"
prepStmtCacheSqlLimit="2048"
maxActive="100"
maxIdle="20"
maxWait="10000"
removeAbandoned="true"
driverClassName="com.mysql.jdbc.Driver"
url="${myURL}"
username="${myUsername}"
password="${myPasswordToResolve}"
factory="my.class.CustomDatabaseConfigurationFactory"
testOnBorrow="true"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="20000"
poolPreparedStatements="true"
maxOpenPreparedStatements="50"
validationQuery="select 1"
validationInterval="60000"
defaultTransactionIsolation="READ_COMMITTED"
/>
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
<Loader loaderClass="org.apache.catalina.loader.ParallelWebappClassLoader" />
<Resource auth="Container"
name="jms/JMSConnectionFactory"
type="org.apache.activemq.pool.PooledConnectionFactory"
description="JMS Connection Factory"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
brokerURL="my.URL"
maxConnections="100"
maximumActiveSessionPerConnection="50"
expiryTimeout="10000"
/>
</Context>
我不会添加我的 my.class.CustomDatabaseConfigurationFactory
的代码,因为我知道它在本地有效。出于某种原因,当我使用远程配置和设置启动它时,Tomcat 完全忽略了我为 JNDI 资源设置的自定义工厂。有什么我必须添加以强制 Tomcat 寻找我的自定义工厂而不是忽略它吗?我在本地的嵌入式 tomcat 实例上使用几乎相同的配置。最重要的是,我在日志中没有看到任何与错误配置文件相关的线索。
这是完整的堆栈跟踪:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [spring/dataaccess/openjpa/openjpa.xml]: Invocation of ini\
t method failed; nested exception is <openjpa-2.4.0-ep2.1-runknown fatal user error> org.apache.openjpa.persistence.ArgumentException: Could not invoke the static newInstance method on the named fact\
ory class "org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory".
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1514)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1119)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:924)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:410)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5118)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5634)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:899)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:875)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:679)
at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1966)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java)
at java.lang.Thread.run(Thread.java:748)
实际上,当自定义数据工厂解析正确的密码时,永远不会出现此问题。
对于遇到此问题的其他人的一些注意事项:
On top of that, I don't see any clues in the logs that are related to
a misconfigured file.
这是一个毫无意义的泄露,表明某些内容未加载或记录器未正确设置。在我意识到 log4j 没有正确配置之后,我能够看到我的工厂实际上正在加载。后来看到结果才知道是数据库密码设置不正确
虽然日志错误级别太高且没有足够详细的信息,但这个问题可以通过基本的调试方法解决,并且可以通过注意日志记录来避免。
我正在做一个需要在 运行 时间解析数据库密码的项目。我通过在 Tomcat 配置中指定 DataSourceFactory
来有效地在本地执行此操作。此过程可防止将任何凭据存储在纯文本配置文件中,并为我们提供自定义控件以在 运行 时间解析密码。我在本地取得了巨大的成功,但是当我将我的解决方案移动到 AWS 上的 real/non-embedded Tomcat 实例时,我看到了这个错误:
Could not invoke the static newInstance method on the named factory class "org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory".
首先,围绕此错误消息有一些可疑的细节。第一(正如您将在下面看到的),尽管其他凭据有效(例如用户名、密码等),但我的工厂 class 在 tomcat 配置文件中被忽略了。
我的 DataSourceFactory
的代码需要引用 class 来解析一个值。
这是我为 tomcat:
<?xml version='1.0' encoding='UTF-8'?>
<Context useHttpOnly="false">
<Resource auth="Container" name="mail/Session" type="javax.mail.Session"/>
<Resource name="jdbc/jndi"
auth="Container"
scope="Shareable"
type="javax.sql.DataSource"
useLocalSessionState="true"
cacheServerConfiguration="true"
useServerPrepStmts="true"
cachePrepStmts="true"
cacheCallableStmts="true"
elideSetAutoCommits="true"
alwaysSendSetIsolation="false"
enableQueryTimeouts="false"
prepStmtCacheSize="250"
prepStmtCacheSqlLimit="2048"
maxActive="100"
maxIdle="20"
maxWait="10000"
removeAbandoned="true"
driverClassName="com.mysql.jdbc.Driver"
url="${myURL}"
username="${myUsername}"
password="${myPasswordToResolve}"
factory="my.class.CustomDatabaseConfigurationFactory"
testOnBorrow="true"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="20000"
poolPreparedStatements="true"
maxOpenPreparedStatements="50"
validationQuery="select 1"
validationInterval="60000"
defaultTransactionIsolation="READ_COMMITTED"
/>
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
<Loader loaderClass="org.apache.catalina.loader.ParallelWebappClassLoader" />
<Resource auth="Container"
name="jms/JMSConnectionFactory"
type="org.apache.activemq.pool.PooledConnectionFactory"
description="JMS Connection Factory"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
brokerURL="my.URL"
maxConnections="100"
maximumActiveSessionPerConnection="50"
expiryTimeout="10000"
/>
</Context>
我不会添加我的 my.class.CustomDatabaseConfigurationFactory
的代码,因为我知道它在本地有效。出于某种原因,当我使用远程配置和设置启动它时,Tomcat 完全忽略了我为 JNDI 资源设置的自定义工厂。有什么我必须添加以强制 Tomcat 寻找我的自定义工厂而不是忽略它吗?我在本地的嵌入式 tomcat 实例上使用几乎相同的配置。最重要的是,我在日志中没有看到任何与错误配置文件相关的线索。
这是完整的堆栈跟踪:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [spring/dataaccess/openjpa/openjpa.xml]: Invocation of ini\
t method failed; nested exception is <openjpa-2.4.0-ep2.1-runknown fatal user error> org.apache.openjpa.persistence.ArgumentException: Could not invoke the static newInstance method on the named fact\
ory class "org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory".
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1514)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1119)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:924)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:410)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5118)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5634)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:899)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:875)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:679)
at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1966)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java)
at java.lang.Thread.run(Thread.java:748)
实际上,当自定义数据工厂解析正确的密码时,永远不会出现此问题。
对于遇到此问题的其他人的一些注意事项:
On top of that, I don't see any clues in the logs that are related to a misconfigured file.
这是一个毫无意义的泄露,表明某些内容未加载或记录器未正确设置。在我意识到 log4j 没有正确配置之后,我能够看到我的工厂实际上正在加载。后来看到结果才知道是数据库密码设置不正确
虽然日志错误级别太高且没有足够详细的信息,但这个问题可以通过基本的调试方法解决,并且可以通过注意日志记录来避免。