第一次接触JNDI,废了好长的时间,遇到了好多莫名奇妙的问题,但是终于配置成功。
下面讲解的JNDI都是局部配置,不是全局的。
从最简单的和网上最长见的JDBC数据源讲起。
配置META-INF/context.xml(在webapp下和WEB-INF文件夹并列),初始内容可以从tomcat配置文件的cof/context.xml文件中复制,然后添加内容
<Resource name="jndi/mybatis"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/自己的数据库"
username="自己的数据库用户名"
password="自己的密码"
maxActive="20"
maxIdle="10"
maxWait="10000"/>
然后配置web.xml文件
添加下面的配置
<resource-ref>
<description>JNDI DataSource</description>
<res-ref-name>jndi/mybatis</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
注意
res-ref-name必须和上面的name相同
然后可以通过下面的代码获取数据源
context = new InitialContext();
DataSource ds = (DataSource) context.lookup("java:comp/env/jndi/mybatis")
进一步,我们是否可以实现通过jndi获取自定义的对象呢?答案是肯定的,但是不是将类实现成bean实现的,而是通过factory类进行实例化
第一步,自定义类和其factory类(实现ObjectFactory接口的类),我将这两者实现在了一个类中。
/**
* Alipay.com Inc.
* Copyright (c) 2004-2014 All Rights Reserved.
*/
package org.footoo.jspTest1;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;
/**
*
* @author jeff
* @version $Id: UserInfo.java, v 0.1 2014年4月19日 下午1:11:27 jeff Exp $
*/
public class UserInfo implements ObjectFactory {
private String userName;
private int id;
/**
* Getter method for property <tt>name</tt>.
*
* @return property value of name
*/
public final String getName() {
return userName;
}
/**
* Setter method for property <tt>name</tt>.
*
* @param name value to be assigned to property name
*/
public final void setName(String name) {
this.userName = name;
}
/**
* Getter method for property <tt>id</tt>.
*
* @return property value of id
*/
public final int getId() {
return id;
}
/**
* Setter method for property <tt>id</tt>.
*
* @param id value to be assigned to property id
*/
public final void setId(int id) {
this.id = id;
}
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable<?, ?> environment) throws Exception {
UserInfo userInfo = new UserInfo();
Reference reference = (Reference) obj;
Enumeration<RefAddr> cfgAddrs = reference.getAll();
while (cfgAddrs.hasMoreElements()) {
RefAddr cfgAddr = cfgAddrs.nextElement();
String attrName = (String) cfgAddr.getType();
String attrValue = (String) cfgAddr.getContent();
if (attrName == "id") {
userInfo.setId(Integer.valueOf(attrValue));
} else if (attrName == "userName") {
userInfo.setName(attrValue);
}
}
return userInfo;
}
}
从上面的代码可以看出,实例化对象时,容器会将配置的属性传递给回调函数,即第一个参数obj中包含的数据。
然后在context.xml中定义类,基本和数据源的配置类似,只是需要定义factory属性
<Resource name="jndi/userInfo"
auth="Container"
type="org.footoo.jspTest1.UserInfo"
userName="jeff"
id="12"
factory="org.footoo.jspTest1.UserInfo"
/>
然后只需要调用下面的方法就可以获得UserInfo的属性(原理和配置数据源一模一样)
context = new InitialContext();
UserInfo userInfo = (UserInfo) context.lookup("java:comp/env/jndi/userInfo");
关于JNDI的补充:
1、jndi本质就是通过factory(实现ObjectFactory接口的)类将配置的属性赋予目标对象
2、对于bean,我们甚至可以通过反射实现其属性的自动赋予。这个感觉就是spring的IOC了