工具类GlobalConfigUtil代码实现过程分析

本文接上一篇:获取xml中key对应的value值 的 工具类GlobalConfigUtil

具体的实现过程分析以注释的形式添加到代码过程中说明: 

import java.lang.reflect.Method;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.beans.factory.config.PropertyResourceConfigurer;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.support.PropertiesLoaderSupport;

public class GlobalConfigUtil {

	private static Logger logger = LoggerFactory.getLogger(GlobalConfigUtil.class);
	private static PropertyPlaceholderConfigurer configure;
	private static Properties properties = null;
	private static String[] path = null;
	private static GlobalConfigUtil globalConfig = null;

	//	构造方法
	private GlobalConfigUtil(String[] path) {
		// 初始化,配置属性到本地properties中区
		try {
			if (properties == null) {
				properties = new Properties();
				/*
				 *	参考博客:https://blog.csdn.net/u013399093/article/details/54922902
				 *  ClassPathXmlApplicationContext类:
				 *  简单的用ApplicationContext做测试的话,获得Spring中定义的Bean实例(对象).可以用:
					ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
					RegisterDAO registerDAO = (RegisterDAO)ac.getBean("RegisterDAO");
					如果是两个以上:
					ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml","dao.xml"});
					或者用通配符:
					ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:/*.xml");
				 */
				ClassPathXmlApplicationContext wapp = new ClassPathXmlApplicationContext(path);
				init(wapp);
			}
		} catch (Exception e) {
			e.printStackTrace();
			// 初始化属性读取失败
			logger.error("Exception:",e);
		}
	}
	private GlobalConfigUtil(){
	}
	//==========================================================================
	/*
	 * 初始化  上下文		
	 */
	public static void initContext(String[] paths) {
		path = paths;
		getInstance();
	}
	/*
	 * 获取实例    instance实例
	 */
	public static GlobalConfigUtil getInstance() {
		if (globalConfig == null) {
			globalConfig = new GlobalConfigUtil(path);
		}
		return globalConfig;
	}
	
	public static void init(ClassPathXmlApplicationContext wapp) {
		try {
			properties = new Properties();
			
			/*
			 * 程序执行到这一步有异常:
			 * org.springframework.beans.factory.NoSuchBeanDefinitionException:
			 * 					 No bean named 'propertyPlaceHolder' is defined    
			 * 异常原因就是自己传错了xml文件。path应该传spring-application.xml
			 * 
			 * getBean方法的参数"propertyPlaceHolder",对应spring的application.xml对调用读取外部xml的配置的id,对应代码如下:
			 * 	<!-- 定义受环境影响易变的变量 -->
			 * 	<bean id="propertyPlaceHolder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
			 *
			 * 关于	PropertyPlaceholderConfigurer  类的介绍  ,参考博客:
			 * https://blog.csdn.net/blueboz/article/details/54808915
			 */
			configure = (PropertyPlaceholderConfigurer) wapp.getBean("propertyPlaceHolder");
			/*
			 * PropertyPlaceholderConfigurer 类  强制转换为  PropertyResourceConfigurer类
			 * PropertyResourceConfigurer类的介绍:
			 */
			PropertyResourceConfigurer propertyResourceConfigurer = (PropertyResourceConfigurer) configure;
			/*
			 * PropertiesLoaderSupport类     参考:https://blog.csdn.net/u013038630/article/details/54094973
			 * PropertiesLoaderSupport的mergeProperties方法混合从文件读取(使用loadProperties方法)的和自身设置进
			 		  去的property,

			    反射  getDeclaredMethod方法返回一个Method对象,它反映此Class对象所表示的类或接口的指定已声明方法。
			 *  参考  https://blog.csdn.net/s445320/article/details/52684898
			 */
			Method mergeProperties = PropertiesLoaderSupport.class.getDeclaredMethod("mergeProperties");
			/*
			 *这一步 setAccessible 参考:https://blog.csdn.net/devilkin64/article/details/7766792    
			 *		提高java反射速度
			 		JDK API中的解释
					引用
					AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、Method 或 Constructor 对象来设置或获得字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查。
					在反射对象中设置 accessible 标志允许具有足够特权的复杂应用程序(比如 Java Object Serialization 或其他持久性机制)以某种通常禁止使用的方式来操作对象。
					setAccessible 
					public void setAccessible(boolean flag) 
					                   throws SecurityException 
					将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。
					实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问
			 */
			mergeProperties.setAccessible(true);
			/*
			 *	Method.invoke()的用法,  参考样例:https://blog.csdn.net/u013473691/article/details/52633800
			 *   
			 */
			Properties props = (Properties) mergeProperties.invoke(propertyResourceConfigurer);
			Method convertProperties = PropertyResourceConfigurer.class.getDeclaredMethod("convertProperties", Properties.class);
			convertProperties.setAccessible(true);
			convertProperties.invoke(propertyResourceConfigurer, props);
			properties.putAll(props);
		} catch (Exception e) {
			// 初始化属性读取失败
			logger.error("Exception:",e);
		}
	}
	
	/*
	 * 获取key对应的value值
	 */
	public String getString(String key) {
		return properties.getProperty(key);
	}
}

需要明确两点比较重要:

① PropertyResourceConfigurer类 是干什么的?在百度上直接搜没有找到和其直接相关的信息介绍。以至于为什么要把

PropertyPlaceholderConfigurer 类  强制转换为  PropertyResourceConfigurer类。

② 就是最下面的Method.invoke()的实现过程的具体分析。


ps:这两点目前还是不明白的,暂时搁置。

猜你喜欢

转载自blog.csdn.net/xiaoanzi123/article/details/79790189