今天同事说我们的后台要支持weblogic的jndi数据源,之前不支持,只要修改下部分代码,之前的代码是这样的.使用的dbcp连接池
dataSource = (BasicDataSource) BasicDataSourceFactory
.createDataSource(SystemContext.getSysProperties());
要支持jndi,首先jndi的配置参数需要3个,分别为jndiName,jndiServer和jndiDriver当然实际配置参数不是这个名字,是INITIAL_CONTEXT_FACTORY和PROVIDER_URL,一般如果应用是发布在服务器下的,不需要这两个参数,只要提供jndi数据源的名称就可以了.连接数据源的代码如下
private static DataSource lookupSource(String jndi, String driver,
String server) {
logger.debug("通过 JNDI 获得数据源:server=" + server + ", jndi=" + jndi);
Context ctx = null;
try {
// 如果没有在配置文件中指定 jndi 配置
if (StringUtils.isNullOrEmpty(driver)
|| StringUtils.isNullOrEmpty(server)) {
ctx = new InitialContext();
} else {
Properties p = new Properties();
if (!StringUtils.isNullOrEmpty(driver)) {
p.put(Context.INITIAL_CONTEXT_FACTORY, driver);
}
if (!StringUtils.isNullOrEmpty(server)) {
p.put(Context.PROVIDER_URL, server);
}
ctx = new InitialContext(p);
}
return (DataSource) (ctx.lookup(jndi));
} catch (NamingException e) {
throw new DBException(e);
}
}
在tomcat的context.xml中配置下数据源
<Resource name="jndi/test"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/task"
username="root" password="xxx" maxActive="200" maxIdle="10"
maxWait="-1"
/>
数据源的名字为jndi/test,在java中获取的为这个即可
启动tomcat,执行测试,出现如下异常。
javax.naming.NameNotFoundException: Name jndi is not bound in this Context
没有找到这个数据源,名字也不太对啊。。我们的是jndi/test。通过google,查看tomcat的官方文档。
http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html,发现官方的示例代码如下
InitialContext cxt = new InitialContext();
if ( cxt == null ) {
throw new Exception("Uh oh -- no context!");
}
DataSource ds = (DataSource) cxt.lookup( "java:/comp/env/jdbc/postgres" );
if ( ds == null ) {
throw new Exception("Data source not found!");
}
原来如此。需要在jndi/test前面加上java:/comp/env/ 。好吧。。加上了。再次运行。果然没有问题了。那么这个java:/comp/env是什么呢。。看起来好像一个环境变量似的。实际他是用来定义资源的,个人理解就好像是命名空间,更多详细的解释稍后再说
修改之后打包发布了。不一会儿同事电话来了,报错。。查看错误日志,发现 依然是绑定的问题,异常提示找不到数据源java,不应该啊。数据源名称和java没有一分钱关系,难道是java:/comp/env/的问题?google下,查看了weblogic的文档,果然如此,去掉tomcat需要的,果然没问题了。
关于这个前缀的详细解释,见http://f543711700.iteye.com/blog/1173618
其实说得简单点:context.lookup("java:comp/env/XXX")只能用在J2EE环境,即是如果你自己写一个main函数,想通过context.lookup("java:comp/env/XXX")这样的方式来访问JNDI服务,这是不可能的
因为:java:comp/env/是一个J2EE环境的定义,说白了就是代表当前J2EE应用的环境,比如你自己项目的Web环境或者是EJB环境,那是不是只要是个Web项目,就能用context.lookup("java:comp/env/XXX")这种方式访问JNDI服务了呢?也不是!!
使用这样的方式必须做一次 当前应用环境 到 资源名 的映射
在web.xml文件中有这样的标签
这些标签就是用来建立当前应用环境到服务器资源的映射的
有了这样的映射之后,就能采用context.lookup("java:comp/env/XXX")的方式来访问JNDI资源了。
注意:context.lookup("XXX")在任何时候都是有效的,只要XXX确实是一个存在的JNDI名。
最后为了两种不同实现的服务器,我们的代码变成了这样.
private static DataSource lookupSource(String jndi, String driver,
String server) {
logger.debug("通过 JNDI 获得数据源:server=" + server + ", jndi=" + jndi);
Context ctx = null;
try {
// 如果没有在配置文件中指定 jndi 配置
if (StringUtils.isNullOrEmpty(driver)
|| StringUtils.isNullOrEmpty(server)) {
ctx = new InitialContext();
} else {
Properties p = new Properties();
if (!StringUtils.isNullOrEmpty(driver)) {
p.put(Context.INITIAL_CONTEXT_FACTORY, driver);
}
if (!StringUtils.isNullOrEmpty(server)) {
p.put(Context.PROVIDER_URL, server);
}
ctx = new InitialContext(p);
}
return (DataSource) (ctx.lookup(jndi));
} catch (NamingException e) {
// 如果私有的jndi资源访问不到,切换到全局的重试一次
try {
if (StringUtils.isNotNullOrEmpty(jndi)
&& !jndi.startsWith("java:comp/env/")) {
jndi = "java:comp/env/" + jndi;
}
return (DataSource) (ctx.lookup(jndi));
} catch (NamingException e1) {
throw new DBException(e);
}
}
}