spring-boot启动源码学习-1
2018-07-05 17:59
405 查看
spring-boot启动源码分析-启动初始化
主要对spring-boot的启动流程中的启动初始化进行学习,学习spring boot的启动流程中的相关知识,如果有分析不对的,欢迎指正1.相关的环境配置
开发工具IDEAJDK1.8
spring-boot 版本 1.5.10
2.启动的入口
spring boot的启动时通过一个main 函数启动的。例如@SpringBootApplication public class OptWalletApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(OptWalletApplication.class,args); } }
@SpringBootApplication 是一个组合注解,其中包含EnableAutoConfiguration(自动注入配置文件),ComponentScan(扫描)
2.进入run方法,看下里面什么内容
//1.点击run以后进入如下方法中 public static ConfigurableApplicationContext run(Object source, String... args) { return run(new Object[] { source }, args);//继续跟踪 } //2.这个才是spring boot干活的地方,其中sources就是在main()中传递过来的 public static ConfigurableApplicationContext run(Object[] sources, String[] args) { return new SpringApplication(sources).run(args); }
3.启动时的初始化
在前面我们看到,spring boot 真正启动的时候 是通过**new SpringApplication(sources).run(args)**进行的。那么在new SpringApplication()中都干了什么呢,点击进入//1.进入SpringApplication的构造函数中 public SpringApplication(Object... sources) { initialize(sources);//初始化相关内容,继续向下看 } //2.初始化内容,对这里面的四个主要的步骤分别分析 private void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } this.webEnvironment = deduceWebEnvironment();//判断运行环境是否是web环境 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));//获取ApplicationContextInitializer setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//获取ApplicationListener this.mainApplicationClass = deduceMainApplicationClass();// 获取mainApplicationClass }
3.1 判断运行环境是否是web环境
进入deduceWebEnvironment()方法
//1.该方法主要有个一个变量值 WEB_ENVIRONMENT_CLASSES,该变量值是什么呢。(我直接贴出来) //WEB_ENVIRONMENT_CLASSES={ "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" } private boolean deduceWebEnvironment() { for (String className : WEB_ENVIRONMENT_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return false; } } return true; } //2.进入ClassUtils.isPresent()方法 public static boolean isPresent(String className, ClassLoader classLoader) { try { forName(className, classLoader); return true; } catch (Throwable var3) { return false; } } //3.可看出,就是通过反射查找你的工程中是否还有javax.servlet.Servlet 和 ConfigurableWebApplicationContext这两个类来判断你当前的工程环境
3.2 获取ApplicationContextInitializer
进入getSpringFactoriesInstances(Class<T> type)方法中查看
//1.该方法没做什么实质的工作,继续向下看(可以学习下java中的泛型,也可以学习下spring 怎么对方法进行重载的) private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) { return getSpringFactoriesInstances(type, new Class<?>[] {}); } //2.做事情的在这个方法里面 private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Use names and ensure unique to protect against duplicates Set<String> names = new LinkedHashSet<String>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));//查找type类型的class name,为下面创建实例做准备 List<T> instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names);//通过上面获取的class name反射创建实例 AnnotationAwareOrderComparator.sort(instances);//进行排序 return instances; }
我们下面看下spring中怎么根据type 查找相关的类名
//1.进入loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));//获取META-INF/spring.factories所在的路径 List<String> result = new ArrayList<String>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));//获取路径下对应的属性值 String factoryClassNames = properties.getProperty(factoryClassName);//获取我们自己想要的class name result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
至于怎么获取spring.factories下面的路径,怎么通过路径进行解析,这里就不在分析了
通过class name 反射出相关的实例
private <T> List<T> createSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes,ClassLoader classLoader, Object[] args,Set<String> names) { List<T> instances = new ArrayList<T>(names.size()); for (String name : names) { try { Class<?> instanceClass = ClassUtils.forName(name, classLoader); Assert.isAssignable(type, instanceClass); Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes); T instance = (T) BeanUtils.instantiateClass(constructor, args); instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException( "Cannot instantiate " + type + " : " + name, ex); } } return instances; }
都是通过反射获取相应的实例
3.3 获取ApplicationListener
获取ApplicationListener和上面的获取ApplicationContextInitializer一样。这里就不做描述了
//1.和3.2 中的内容差不多,所以不做分析了 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
3.4 获取mainApplicationClass
这个方法没什么好看的
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; }
4.到此spring boot启动中有关初始的化的内容已经分析完毕,下篇对run方法进行分析
相关文章推荐
- spring-boot启动源码学习-2
- spring-boot启动源码学习-3
- spring boot学习1之main和tomcat启动及log日志
- 通过实例及源码分析关于SpringBoot启动类启动时自动配置问题
- Springboot启动源码详解
- [Spring Boot] 1. Spring Boot启动过程源码分析
- spring boot源码学习 SpringApplication(一)
- spring源码学习之:spring容器的applicationContext启动过程
- Spring Boot启动过程源码分析
- Spring Boot学习笔记03--深入了解SpringBoot的启动过程
- Springboot 源码解析(启动时)
- TQ2440 学习笔记—— 30、移植U-Boot【U-Boot 的启动过程第一阶段源码分析】
- springboot学习之启动类中的@SpringBootApplication注解
- 学习spring-boot第一节demo运行与web启动
- Springboot启动源码详解
- Spring学习日志-简单springboot入门启动
- Springboot启动源码详解
- Spring boot源码分析-AnnotationConfigApplicationContext非web环境下的启动容器(2)
- TQ2440 学习笔记—— 31、移植U-Boot【U-Boot 的启动过程第二阶段源码分析】