本帖主要内容
本帖的主要讲述使用JNDI方法使多个java工程之间相互独立。
在实际应用中,我们总是希望有一个单独的工程(jar包)负责专门对外连接数据库、读取配置文件,而其他更高级的工程不关注于此等底层连接而专门处理各自的业务,以实现各个工程的功能单一化。JNDI能够帮助读者实现该功能,本文也正是要介绍该点。
demo假设
1. 假设我们建立一个单独的COMMON工程以专门负责读取配置文件cham.xml;
2. 我们建立另外一个上层应用工程Chamt,用于实现业务并对外提供。
总结:我们希望在Chamt工程中获取COMMON工程负责读取的配置文件。
工程搭建
1.COMMON工程搭建
COMMON工程的目的在于读取指定目录(/conf/)下的cham.xml配置文件。
java代码读取配置文件的方法请参见 https://blog.csdn.net/beitian_123/article/details/80087021帖子,此处不再赘述。
1.1 创建serverInitor.java文件,用于初始化
下面代码中init函数的入参 configPath即为配置文件的路径,在tomcat工程中一般放置在/conf/目录下,可以通过System.getProperty("catalina.base");方法以获取配置文件的路径。
ConfigParse.java类用于读取配置文件
package com.common.initor.startup;
import com.common.initor.config.ConfigParse;
import com.common.initor.config.SystemConfig;
import com.common.initor.resources.StaticResource;
public class ServerInitor {
private static boolean beInit = false ;
public static void init(String configPath) {
//所有初始化的开始
if(true == beInit) {
System.out.println("ServerInit has been inited");
return;
}
beInit = true;
ConfigParse configParse = new ConfigParse(configPath);
SystemConfig config = configParse.getConfig();
//System.out.println("the config is = " + config);
StaticResource.setConfig(config);//将config设置到公共资源包中
}
}
package com.common.initor.config;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import org.xml.sax.InputSource;
/**
* Add by beitian for init cham.xml
*/
public class ConfigParse {
private String configPath;
private String configFile;
private SystemConfig config;
public ConfigParse(String configPath) {
if(null == configPath) {
return;
}
this.initConfigFile(configPath);
this.initConfig();
}
/**
* 初始化路径,将configPath的路径设置为/conf/路径
*/
private void initConfigFile(String configPath) {
if(!configPath.endsWith(File.separator)) {
//如果路径不是以 / 结尾,则加上 结尾符及 conf
this.configPath = configPath + File.separatorChar + "conf" + File.separatorChar;
}else {
//如果有结尾符,则直接加 conf 即可
this.configPath = configPath + "conf" + File.separatorChar;
}
//指定读取conf/路径下的cham.xml配置文件
this.configFile = this.configPath + "cham.xml";
}
/**
* 负责读取cham.xml文件并存储于 config 变量中。该内容之前的帖子中已经讲解,此处不赘述
*/
private void initConfig() {
try {
JAXBContext context = JAXBContext.newInstance(SystemConfig.class);//首先创建SystemConfig.java的模型
Unmarshaller umar = context.createUnmarshaller();
File file = new File(this.configFile);
InputStream inputStream = new FileInputStream(file);//通过输入流读取配置文件
InputSource source = new InputSource(inputStream);
source.setEncoding("UTF-8");//设置读取字节的方式
this.config = (SystemConfig)umar.unmarshal(inputStream);
}catch(Exception e) {
System.out.println("initConfig failed : " + e.toString());
}
}
public SystemConfig getConfig() {
return this.config;
}
}
上面所讲类的作用用于读取配置文件,在之前的帖子中已经讲解,请参考。
COMMON类本身就是要作为一个公共的对象对外提供,所以我们可以使用static创建一个公共的类,负责存储我们读取到的配置文件的内容。
package com.common.initor.resources;
import com.common.initor.config.SystemConfig;
public class StaticResource {
//config作为公共变量,专门用于存储读取到的cham.xml配置文件中的内容,以使更高层使用
private static SystemConfig config;
public static SystemConfig getConfig() {
return config;
}
public static void setConfig(SystemConfig config) {
StaticResource.config = config;
}
}
上面三个文件可以实现读取cham.xml配置文件,但是ServerInitor.java需要有一个触发点,我们不妨建立一个FactoryResource类来驱动读取配置文件
package com.common.initor.resources;
import com.common.initor.config.SystemConfig;
import com.common.initor.startup.ServerInitor;
public class FactoryResource {
public static SystemConfig config;
static {
//获取/conf/上层目录
String configPath = System.getProperty("catalina.base");
try {
//读取配置文件
ServerInitor.init(configPath);
//将读取到的内容作为公共变量
FactoryResource.config = StaticResource.getConfig();
}catch(Exception e) {
System.out.println("FactoryResources : " + e.toString());
}
}
}
JNDI工程:要想使上层能够通过JNDI获取到底层的配置文件,则底层必须提供工厂方法,即 实现 ObjectFactory类
package com.common.initor.jndi;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import com.common.initor.resources.FactoryResource;
public class SystemConfigFactory implements ObjectFactory{
@Override
public Object getObjectInstance(Object arg0, Name arg1, Context arg2, Hashtable<?, ?> arg3) throws Exception {
if(null != FactoryResource.config) {
//将配置文件内容通过server.xml中配置的factory返回给上层调用者
return FactoryResource.config;
}
System.out.println("SystemConfigFactory is null");
return null;
}
}
2.导出jar包
选中COMMON工程,右键选择 Export,在Java选项下选择 JAR file,具体操作请到网上搜索出包流程。
将生成的jar包放置在chamt工程tomcat工程所在的 lib 路径下。
3. 上层CHAMT工程搭建
至此,底层已经成功读取配置文件并将内容返回给上层;上层工程能做的就是讲读取文件通过配置获取
CHAMT工程的server.xml配置
1. 全局配置
在server.xml的<GlobalNamingResources/>节点下添加全局变量:下面代码中第二行是此次添加内容
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
<Resource auth="Container" factory="com.common.initor.jndi.SystemConfigFactory" name="cham/test" pathname="conf/tomcat-users.xml" type="com.common.initor.config.SystemConfig"/>
</GlobalNamingResources>
2. 局部配置
在server.xml中的<Host/>节点下添加<Context/>节点,chamt工程可以通过该Context节点获取COMMON的配置文件
<Host appBase="webapps" autoDeploy="false" name="localhost" unpackWARs="true">
<Context crossContext="false" docBase="CHAMT" path="/CHAMT" privileged="false" reloadable="false" useHttpOnly="true">
<WatchedResource>
WEB-INF/web.xml
</WatchedResource>
<Manager pathname=""/>
<ResourceLink global="cham/test" name="cham/test" type="com.common.initor.config.SystemConfig"/>
</Context></Host>
3. java中读取
上述server.xml配置完成以后,我们可以通过java代码直接读取<Context/>节点的内容
@RequestMapping(value="/index.html")
public String loginPage() throws NamingException
{
System.out.println("+++++++++hello world, hello china+++++++++++");
/*String configPath = System.getProperty("catalina.base");
ServerInitor.initBasic(configPath);*/
Context initContext = new InitialContext();
System.out.println("SystemConfig === " + initContext.lookup("java:comp/env/cham/test"));
return "login";
}
因工作中用到,顺便进行总结,如果不适用读者,请另行参考。