准备:
预先了解的知识, https://www.cnblogs.com/theRhyme/p/11057233.html
问题列表:
1:springboot启动过程中如何加载META-INF/spring.factories
2:springboot启动过程中都哪些地方用到了META-INF/spring.factories,分别起了什么作用。
3:ApplicationContextInitializer的作用,其子类都有哪些及作用分别是什么?
4:ApplicationListener的作用,其子类都有哪些及作用分别是什么,有多少种配置方式,二次调用是什么问题?
5:ApplicationEvent的子类有哪些?spring如何监听自定义event?
6: SpringApplicationRunListener的作用,其子类都有哪些,并起哪些作用,已有哪些?
7: webApplicationType 有几种?识别方式怎么实现的。
8:如何获取运行中的主程序类?
9:如何配置java.awt.headless 模式
10:org.springframework.util.MultiValueMap的使用方式及使用场景
11: springboot如何解析命令行参数?
12: 为什么SpringBoot中main方法执行完毕后程序不会直接退出?
解答:
1:springboot启动过程中如何加载META-INF/spring.factories
List<String> s = SpringFactoriesLoader.loadFactoryNames(type, classLoader);
1.1 使用的classLoader是什么?
classLoader=sun.misc.Launcher.AppClassLoader
2: 会读取到哪些spring.factories文件
- ${project_home}/target/classes/META-INF/spring.factories
- ${maven_repository}/org/springframework/spring-beans/5.2.4.RELEASE/spring-beans-5.2.4.RELEASE.jar!/META-INF/spring.factories
- ${maven_repository}/org/springframework/boot/spring-boot-autoconfigure/2.2.5.RELEASE/spring-boot-autoconfigure-2.2.5.RELEASE.jar!/META-INF/spring.factories
- ${maven_repository}/org/mybatis/spring/boot/mybatis-spring-boot-autoconfigure/2.1.1/mybatis-spring-boot-autoconfigure-2.1.1.jar!/META-INF/spring.factories
- ${maven_repository}/com/alibaba/druid-spring-boot-starter/1.2.1/druid-spring-boot-starter-1.2.1.jar!/META-INF/spring.factories
- ${maven_repository}/org/springframework/boot/spring-boot/2.2.5.RELEASE/spring-boot-2.2.5.RELEASE.jar!/META-INF/spring.factories
- ${maven_repository}/com/github/pagehelper/pagehelper-spring-boot-autoconfigure/1.2.12/pagehelper-spring-boot-autoconfigure-1.2.12.jar!/META-INF/spring.factories
3: ApplicationContextInitializer的作用,其子类都有哪些及作用分别是什么?
0 = "org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer"
1 = "org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener"
2 = "org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer"
3 = "org.springframework.boot.context.ContextIdApplicationContextInitializer"
4 = "org.springframework.boot.context.config.DelegatingApplicationContextInitializer"
5 = "org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer"
6 = "org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer"
7 = "org.springframework.boot.devtools.restart.RestartScopeInitializer"
4:ApplicationListener的作用,其子类都有哪些及作用分别是什么,有多少种配置方式,二次调用是什么问题?
- org.springframework.boot.devtools.restart.RestartApplicationListener
- org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor
- org.springframework.boot.context.config.ConfigFileApplicationListener
- org.springframework.boot.context.config.AnsiOutputApplicationListener
- org.springframework.boot.context.logging.LoggingApplicationListener
- org.springframework.boot.autoconfigure.BackgroundPreinitializer
- org.springframework.boot.context.logging.ClasspathLoggingApplicationListener
- org.springframework.boot.context.config.DelegatingApplicationListener
- org.springframework.boot.builder.ParentContextCloserApplicationListener
- org.springframework.boot.ClearCachesApplicationListener
- org.springframework.boot.context.FileEncodingApplicationListener
- org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
- org.springframework.boot.devtools.logger.DevToolsLogFactory.Listener
4.2 ApplicationListener有好多种配置方式,参考网址
4.3 ApplicationListener二次调用的问题,参考网址
5:ApplicationEvent的子类有哪些?spring如何监听自定义event?
5.1 ApplicationEvent的子类有哪些?我们参考网址
5.2 spring如何监听自定义event?参考网址
6: SpringApplicationRunListener的作用,其子类都有哪些,并起哪些作用,已有哪些?
- org.springframework.boot.context.event.EventPublishingRunListener
7: webApplicationType 有几种?识别方式怎么实现的。
7.1 有三类,分别如下:
- NONE: The application should not run as a web application and should not start an embedded web server.
- SERVLET: The application should run as a servlet-based web application and should start an embedded servlet web server.
- REACTIVE: TThe application should run as a reactive web application and should start an embedded reactive web server.
7.2 实现方式参考:WebApplicationType.deduceFromClasspath();
8:如何获取运行中的主程序类?
8.1 参考SpringApplication.deduceMainApplicationClass。代码片段如下:
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
9:如何配置java.awt.headless 模式
参考SpringApplication.configureHeadlessProperty()。什么是 何时使用,如何使用参考如下链接。
代码片段如下:
private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
10:org.springframework.util.MultiValueMap的使用方式及使用场景
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
@Slf4j
public class MultiValueMapTest {
/***
* 从配置文件中加载
* @throws IOException
*/
@Test
public void test1() throws IOException {
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
InputStream inputStream = ClassLoader.getSystemResourceAsStream("multivaluemap.properties");
Properties properties = new Properties();
properties.load(inputStream);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
log.info("key==="+factoryTypeName+"-----------"+factoryImplementationName.trim());
//log.info("----key={},v={}", factoryTypeName.trim(),factoryImplementationName.trim());
map.add(factoryTypeName,factoryImplementationName.trim());
}
}
printMap(map);
}
/**
* 手动增加
* @throws IOException
*/
@Test
public void test2() throws IOException {
MultiValueMap mailMap = new LinkedMultiValueMap<String, String>();
mailMap.add("name","test1");
mailMap.add("name","test2");
mailMap.add("name","test3");
printMap(mailMap);
//返回的类为 java.util.LinkedList
String cname = mailMap.get("name").getClass().getCanonicalName();
log.info("cname={}",cname);
log.info("移除remove2={}",mailMap.remove("name"));
}
private void printMap(MultiValueMap<String, String> map){
Set<String> keySet = map.keySet();
List<String> tempList = null;
String tempValue = null;
for(String key : keySet){
tempList = map.get(key);
Iterator ii = tempList.iterator();
while(ii.hasNext()){
tempValue= (String) ii.next();
log.info("-----key="+key+",value="+tempValue);
}
}
}
}
11: springboot如何解析命令行参数?
采用SimpleCommandLineArgsParser类来解析参数,根据是否是--开头,将--开头的参数放入optionArgs属性里,其他的放入nonOptionArgs属性里。
12: 为什么SpringBoot中main方法执行完毕后程序不会直接退出?
因为有非守护线程在持续运行。具体参考链接。附带新知识点:守护线程与非守护线程的区别
补充知识:
classLoader可通过三种方式获得,而且可以依次降级。分别为:
1)Thread.currentThread().getContextClassLoader();
2)ClassUtils.class.getClassLoader();
3)ClassLoader.getSystemClassLoader();
其中1)的getSystemResources(“a.txt”)是从系统的根目录里查找资源
classLoader方法标识
获取classloader的方法 加载根目录资源 加载本目录下寻找资源 备注 Thread.currentThread().getContextClassLoader() getSystemResources(“a.txt”)
*********************** 无
getResources("a.txt")
无法从根目录和当前目录中加载到任何资源
ClassUtils.class.getClassLoader() getSystemResources(“a.txt”) *********************** 无
getResources("a.txt")
无法从根目录和当前目录中加载到任何资源
ClassLoader.getSystemClassLoader() getSystemResources(“a.txt”) *********************** 无
getResources("a.txt")
无法从根目录和当前目录中加载到任何资源
2, 四种常见的线程池详解,请点击链接
2.1 知识点,共享的无界队列,自定义线程池。链接1,链接2.
工具方法:
1:加载项目中的property文件
1.1 采用PropertiesLoaderUtils方法
1.2 采用 properties.load(inputStream)方法,具体代码如下
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.core.io.UrlResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
@Slf4j
public class PropertiesLoaderUtilsTest {
@Test
public void loadProperties1() throws IOException {
URL url = ClassLoader.getSystemResource("a.properties");
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
printPropertys( properties);
}
@Test
public void loadProperties2() throws IOException {
InputStream inputStream = ClassLoader.getSystemResourceAsStream("a.properties");
Properties properties = new Properties();
properties.load(inputStream);
printPropertys( properties);
}
private void printPropertys(Properties properties){
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String key = ((String) entry.getKey()).trim();
//spring内部写法
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
log.info("key={},v={}", key.trim(),factoryImplementationName.trim());
}
//本人常规写法
String v2 = (String) entry.getValue();
log.info("-----------key={},v={}", key.trim(),v2);
}
}
}