一.问题描述
最近项目需要对接其他公司的接口(SDK方式对接),SDK接入时需要特定的四个配置属性,该配置属性通过web.xml获取。在自己电脑调试通过之后,jar部署到服务器后发现无法正确读取到web.xml的内容。
由于没有日志的打印,所以不知道是因为路径不对还是什么原因导致无法正确读取web.xml(web.xml内容的读取代码在SDK依赖中)。于是只好自己本地覆盖依赖类,加上路径的日志打印。经过一番操作之后,发现打印的路径有问题,然后修改代码获取正确的路径还是无法读取web.xml。无奈,只能将四个配置放到配置文件中获取了。
二.解决思路
1 覆盖SDK依赖中获取web.xml内容的类,自己修改代码;
2 将四个配置属性放到配置文件获取;
三.解决方案
1 本地类覆盖依赖的类
只需要在自己的项目中建一个包路径、类名和依赖类完全相同的类即可。比如,依赖类的包路径 com.test.guess,类名为TestClazz,则在自己的项目新建一个包com.test.guess,将自己建的TestClazz类放到这个包下面即可(包路径、类名相同)。jar运行时,如果包路径、类名相同,则以项目中的优先。
2 通过工具类获取配置文件中的配置属性
(1)创建工具类
其实jar启动时,spring会获取很多属性放到ApplicationContext上下文对象中(其中就包括配置文件的属性)。那么我们只需要在自己的项目中创建一个工具类就很容易处理了。工具类如下:
public class CommonUtils {
//ApplicationContext对象
public static ApplicationContext ac;
private static Logger log = LoggerFactory.getLogger(CommonUtils.class);
public CommonUtils() {
}
public static Object getBean(String name) {
return StringUtils.isNoneBlank(new CharSequence[]{name}) ? ac.getBean(name) : null;
}
public static void setApplicationCtx(HttpServletRequest request) {
if (ac == null) {
log.info("ApplicationContext未被初始化");
}
Environment env = ac.getEnvironment();
MutablePropertySources sources = ((ConfigurableEnvironment)env).getPropertySources();
Iterator var4 = sources.iterator();
while(var4.hasNext()) {
PropertySource<?> propertySource = (PropertySource)var4.next();
String key = propertySource.getName();
if (key.indexOf("ckcest.js.") > -1) {
request.setAttribute(key.replace("ckcest.js.", ""), propertySource.getProperty(key));
}
}
request.setAttribute("ctx", request.getContextPath());
}
//获取配置的方法
public static String getProperty(String name) {
return ac.getEnvironment().getProperty(name);
}
}
(2)工具类的ApplicationContext赋予实例
工具类有了,但是有个问题,如何让ac指向spring管理的ApplicationContext对象呢?需要如下处理:
① 启动类加上@ServletComponentScan注解(加上这个注解,@WebListener才有效)
② 监听,工具类的ac对象赋值
@WebListener
public class MyServletContextListener implements ServletContextListener {
public MyServletContextListener() {
}
public void contextInitialized(ServletContextEvent sce) {
ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext());
//赋值
CommonUtils.ac = ctx;
}
public void contextDestroyed(ServletContextEvent sce) {
}
}
(3)获取配置源码查看
处理逻辑是在org.springframework.core.env下的PropertySourcesPropertyResolver类的getProperty方法。方法中会遍历PropertySourcesPropertyResolver的PropertySource属性
大致看下propertySource都有哪些属性吧
第一个属性是项目的端口
第二个属性就是配置文件的内容了:
注意:
PropertySource<?> propertySource = (PropertySource)var4.next();
Object value = propertySource.getProperty(key);
遍历获取下一个propertySource元素的时候,是带有泛型的,所以getProperty的逻辑不一样!这也是为什么,上面第一个元素和第二个元素的属性“结构”不同,但是还能获取的原因。具体的就要各位看官自己去看源码了。
完成以上步骤后,在服务器重试,对接正常。完美!
四.小结
1自己的项目覆盖某个依赖类,需要新建一个包名、类型相同的类即可;其实就是类加载机制;
2ApplicationContext会保存项目各种属性(最常用的配置文件等)
3为什么不用@value注解获取?
有两点原因
(1)因为SDK中被我覆盖的类,所有方法和属性都是static的。SDK其他类调用的时候该类的方法,是通过静态方法调用;
(2)工具类是公司框架现场的;