文章只记录技术方面,本人只有一年多经验没有包装简历,面的岗位要求是3-5年要求技术栈就是常见那些,自研小规模公司hr说让我面面看,然后就很受打击,一上来就问的这些然后,就聊了8min,谈了下薪资不太满意就结束了
1.说一下eureka和nacos的区别?
2.redis、kafak等mq中间件有用过嘛
3.springboot的启动过程
4.jdbc的启动过程
5.stringbuffer和stringbuild的区别,共同继承的类和实现的接口
6.aop原理
7.动态代理原理
8.sql优化操作
9.有分库分表嘛
3.springboot启动过程主要通过SpringApplication的static run方法进行SpringApplication的实例化操作
然后再针对实例化对象调用另外一个run方法完成项目初始化和启动。
先说实例化操作
public SpringApplication(Class>... primarySources) {
this(null, primarySources);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
1.赋值成员变量resourceLoader
资源加载接口,项目启动时打印banner信息,默认值DefaultResourceLoader,默认加载路径也是classpath:
2.赋值成员变量primarySources这也是构造方法的第二个参数,默认传入springboot入口类,也可以是其他类,需要被@EnableAutoConfiguration标注,@SpringBootApplication包含该注解,所以也可以。如果传入不包含上述注解的普通类,那么springboot的自动配置不会开启
3.推断web应用类型 private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
servlet类都不存在就是reactive类型
当String数组中任意一个类不存在时,就是None(自己看吧,就在上面代码块,打字太多了)
最后返回servlet类型
4.加载并初识化ApplicationContextInitializer及相关实现类package org.springframework.context; public interface ApplicationContextInitializer{ void initialize(C var1); }
这个接口就定义了一个方法,主要是为了初始化上下文(ConfigurableApplicationContext的ApplicationContext的refresh方法调用刷新之前对ConfigurableApplicationContext实例进行设置或者处理)
入参有限定符,他的子类
工作分为两步获得实例和设置实例
通过SpringFactoriesLoader类的loadFactoryNames方法获得META-INF/spring.factories文件中注册对应配置
获取到配置类全限定名后,调用createSpringFactoriesInstances方法进行实例化
然后调用setInitializers方法将实例化的集合添加到SpringApplication的成员变量Initializers中,直接new赋值的,每次调用会直接覆盖,目前开发没涉及到这个问题,小记一下
5.加载并初始化ApplicationListener及相关实现类package org.springframework.context; import java.util.EventListener; @FunctionalInterface public interface ApplicationListenerextends EventListener { void onApplicationEvent(E var1); }
事件的监听,最近写aop拦截第三方jar的sql遇到困难,写了全限定名甚至方法依然拦截不到,自己写的类都可以,不晓得这个监听可不可以借鉴一下
流程和上面一样,将结果赋值给listeners
6.推断main方法 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;
}
引用自身的deduceMainApplicationClass方法
先创建运行时异常,获取栈数组,进行遍历
遍历时如果有含有main方法的类就直接进行赋值,如果遍历时有异常会忽略
下一步就是run方法啦



