JNDI用法之一:分层使用读取配置文件

本帖主要内容

    本帖的主要讲述使用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";
	}
因工作中用到,顺便进行总结,如果不适用读者,请另行参考。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值