Java 定制的Tomcat JNDI数据源
我有多个使用同一数据库的Web应用程序。直到最近,我一直在使用JNDI数据源,如下所示: server.xml:Java 定制的Tomcat JNDI数据源,java,spring,tomcat,datasource,jndi,Java,Spring,Tomcat,Datasource,Jndi,我有多个使用同一数据库的Web应用程序。直到最近,我一直在使用JNDI数据源,如下所示: server.xml: <Resource name="jdbc/dbPool" auth="Container" type="javax.sql.DataSource" maxActive="100" minIdle="10" maxIdle="30" maxWait="1000" username="username" password="password
<Resource name="jdbc/dbPool" auth="Container" type="javax.sql.DataSource"
maxActive="100" minIdle="10" maxIdle="30" maxWait="1000"
username="username" password="password"
driverClassName="oracle.jdbc.OracleDriver"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
url="jdbc:oracle:thin:@//localhost:1521/XE"/>
<Resource name="jdbc/dbPool" auth="Container" type="my.webapp.CustomDataSource"
maxActive="100" minIdle="10" maxIdle="30" maxWait="1000"
username="username" password="password"
driverClassName="oracle.jdbc.OracleDriver"
factory="my.webapp.CustomDataSourceFactory"
dialect="org.hibernate.dialect.Oracle10gDialect"
url="jdbc:oracle:thin:@//localhost:1521/XE"/>
现在我需要开始在JNDI资源中配置数据库方言(到目前为止已经硬编码)。我的Tomcat和服务器配置现在如下所示:
server.xml:
<Resource name="jdbc/dbPool" auth="Container" type="javax.sql.DataSource"
maxActive="100" minIdle="10" maxIdle="30" maxWait="1000"
username="username" password="password"
driverClassName="oracle.jdbc.OracleDriver"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
url="jdbc:oracle:thin:@//localhost:1521/XE"/>
<Resource name="jdbc/dbPool" auth="Container" type="my.webapp.CustomDataSource"
maxActive="100" minIdle="10" maxIdle="30" maxWait="1000"
username="username" password="password"
driverClassName="oracle.jdbc.OracleDriver"
factory="my.webapp.CustomDataSourceFactory"
dialect="org.hibernate.dialect.Oracle10gDialect"
url="jdbc:oracle:thin:@//localhost:1521/XE"/>
这在某种程度上是可行的——当我重新启动Tomcat时,第一个webapp(例如使用jdbc/service1DB数据源的webapp)成功启动,并使用配置的方言正常运行,但所有其他webapp在数据源查找过程中都失败并出现错误。此外,当我在不重新启动Tomcat的情况下部署webapp时,也会发生相同的错误(即使是之前在重新启动Tomcat后成功启动的第一个webapp):
这里可能有什么问题?singleton=“false”
啊,我知道了
我确实注意到,CustomDataSource只创建了一个“实例”——重启后,日志中有一个很小的指示,说明创建了数据源,然后启动了第一个webapp,但在再次重启之前,没有为任何webapp再次创建数据源
我重新阅读了Tomcat的JNDI resources HOW-TO中的“添加定制资源工厂”一章,并注意到关于将singleton属性设置为false的评论(我以前读过,但认为这对我的案例并不重要)
我把它添加到我的数据源中。请注意底部的最后一个属性
<Resource name = "jdbc/dbPool"
auth = "Container"
type = "my.webapp.CustomDataSource"
maxActive = "100"
minIdle = "10"
maxIdle = "30"
maxWait = "1000"
username = "username"
password = "password"
driverClassName = "oracle.jdbc.OracleDriver"
factory = "my.webapp.CustomDataSourceFactory"
dialect = "org.hibernate.dialect.Oracle10gDialect"
url = "jdbc:oracle:thin:@//localhost:1521/XE"
singleton = "false"
/>
而且它有效!我的所有网络应用程序都会启动并使用我配置的方言 您的
CustomDataSource
位于哪里?这是Tomcat如何处理类加载器的典型问题,尝试将类放在jar上,Tomcat/libIt中的jar与配置数据源查找的类(以及CustomDataSourceFactory)位于同一个包中。因此,它被包括在每个webapp的战争中。我将尝试这个方法,看看它是否有效,但如果可能的话,我宁愿避免使用这种方法。
public class CustomDataSourceFactory extends DataSourceFactory {
private static final String PROP_DIALECT = "dialect";
private static final String[] CUSTOM_PROPERTIES = new String[]{PROP_DIALECT};
private static final String[] PROPERTIES = ArrayUtils.addAll(ALL_PROPERTIES, CUSTOM_PROPERTIES);
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
if (obj != null && obj instanceof Reference) {
Reference ref = (Reference) obj;
Properties properties = new Properties();
for (int i = 0; i < PROPERTIES.length; ++i) {
String propertyName = PROPERTIES[i];
RefAddr ra = ref.get(propertyName);
if (ra != null) {
String propertyValue = ra.getContent().toString();
properties.setProperty(propertyName, propertyValue);
}
}
return this.createDataSource(properties, nameCtx);
} else {
return null;
}
}
public javax.sql.DataSource createDataSource(Properties properties, Context context) throws Exception {
PoolConfiguration poolProperties = parsePoolProperties(properties);
if (poolProperties.getDataSourceJNDI() != null && poolProperties.getDataSource() == null) {
this.performJNDILookup(context, poolProperties);
}
String dialect = properties.getProperty(PROP_DIALECT);
if (dialect == null) {
log.error("Dialect is unspecified");
return null;
}
CustomDataSource dataSource = new CustomDataSource(dialect, poolProperties);
dataSource.createPool();
return dataSource;
}
}
@NoArgsConstructor
public class CustomDataSource extends DataSource {
@Getter
@Setter
private String dialect;
public CustomDataSource(String dialect, PoolConfiguration poolProperties) {
super(poolProperties);
this.dialect = dialect;
}
}
"org.springframework.jdbc.datasource.lookup.DataSourceLookupFailureException":"Failed to look up JNDI DataSource with name 'java:comp/env/jdbc/service2DB'; nested exception is javax.naming.NamingException: The local resource link [service2DB] that refers to global resource [jdbc/dbPool] was expected to return an instance of [my.webapp.CustomDataSource] but returned an instance of [my.webapp.CustomDataSource]"
<Resource name = "jdbc/dbPool"
auth = "Container"
type = "my.webapp.CustomDataSource"
maxActive = "100"
minIdle = "10"
maxIdle = "30"
maxWait = "1000"
username = "username"
password = "password"
driverClassName = "oracle.jdbc.OracleDriver"
factory = "my.webapp.CustomDataSourceFactory"
dialect = "org.hibernate.dialect.Oracle10gDialect"
url = "jdbc:oracle:thin:@//localhost:1521/XE"
singleton = "false"
/>