摘要:在实际项目开发中使用springboot的时候,可以使用jar包的方式运行项目,也可以将springboot项目打成war包使用。springboot war包运行可能会出现 [localhost-startStop-1] DEBUG org.springframework.jndi.JndiLocatorDelegate - Converted JNDI name [java:comp/env/LOGGING.pattern_level] not found - trying original name [LOGGING.pattern_level]. javax.naming.NameNotFoundException: Name [LOGGING.pattern_level] is not bound in this Context. Unable to find [LOGGING.pattern_level]
。反正就是诸如此类的问题吧。
上述的问题,在高版本的spring boot中会出现的,低版本不会出现这个问题。因为高版本中引入了JNDI查询的操作。
解决方案:
在项目的根目录中新建spring.properties配置文件,如下图所示:
添加属性以及值,如下所示:
spring.jndi.ignore=true
原理
打开StandardServletEnvironment类,该类中的customizePropertySources方法如下:
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
}
super.customizePropertySources(propertySources);
}
JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()代码如下:
public static final String IGNORE_JNDI_PROPERTY_NAME = "spring.jndi.ignore";
private static final boolean shouldIgnoreDefaultJndiEnvironment =
SpringProperties.getFlag(IGNORE_JNDI_PROPERTY_NAME);
public static boolean isDefaultJndiEnvironmentAvailable() {
//如果忽略jndi则返回false
if (shouldIgnoreDefaultJndiEnvironment) {
return false;
}
try {
//准备jndi环境
new InitialContext().getEnvironment();
return true;
}
catch (Throwable ex) {
return false;
}
}
通过上文可知:
1、如果我们需要忽略jndi则可以配置spring.jndi.ignore值为true即可。
2、在哪里配置呢?我们不妨跟进SpringProperties类中的getFlag方法。
spring.jndi.ignore获取原理
SpringProperties类的getFlag方法如下所示:
public static boolean getFlag(String key) {
return Boolean.parseBoolean(getProperty(key));
}
继续跟进getProperty方法,如下所示:
public static String getProperty(String key) {
//获取spring.jndi.ignore值
String value = localProperties.getProperty(key);
if (value == null) {
try {//获取系统的变量
value = System.getProperty(key);
}
catch (Throwable ex) {
}
}
return value;
}
上述的方法可以总结如下:
从localProperties集合中获取spring.jndi.ignore属性,如果没有获取到则直接从环境变量中进行获取。localProperties集合在哪里初始化的呢?我们看一下SpringProperties类中的静态代码块,如下所示:
private static final String PROPERTIES_RESOURCE_LOCATION = "spring.properties";
static {
try {
ClassLoader cl = SpringProperties.class.getClassLoader();
URL url = (cl != null ? cl.getResource(PROPERTIES_RESOURCE_LOCATION) :ClassLoader.getSystemResource(PROPERTIES_RESOURCE_LOCATION));
if (url != null) {
logger.info("Found 'spring.properties' file in local classpath");
InputStream is = url.openStream();
try {
localProperties.load(is);
}
finally {
is.close();
}
}
}
catch (IOException ex) {
}
}
看到上面的代码,我们明白了,原来这里是直接读取跟目录中的spring.properties文件中的所有属性。看到这里,焕然大悟。原来如此。