原始ssm方式,web.xml中的配置
<!--加载springioc容器,创建Bean--><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 配置SpringMVC核心过滤器,拦截所有的http请求 --><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param></servlet>
为什么spring-boot的jar可以直接运行?
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
做了两件事:
- 1)编写manifest.mf

2)打的jar包内再打入jar,fat jar,依赖的jar包也打包进jar内
Java没有提供任何标准的方式来加载嵌套的jar文件(即,它们本身包含在jar中的jar文件),就是没办法加载依赖
还需要manifest.mf文件内配置的Main-Class来加载jar包内的jar文件以及class文件,自定义了类加载器去加载
启程的时候先找到Main-Class,进行依赖的jar进行加载,加载完成之后,再找到Start-Class利用反射调用本应用程序的main方法
总结:
- 通过spring-boot-plugin 生成MANIFEST.MF文件,文件内有个重要的属性main-class,指定运行java -jar的主程序,把依赖的jar文件打包在fat jar,运行java -jar,就会运行JarLauncher。
- JarLauncher通过加载BOOT-INF/classes目录及BOOT-INF/lib目录下jar文件,实现了fat jar的启动。
- SpringBoot通过扩展JarFile、JarURLConnection及URLStreamHandler,实现了jar in jar中资源的加载。
- SpringBoot通过扩展URLClassLoader–LauncherURLClassLoader,实现了jar in jar中class文件的加载。
spring boot启动spring容器
refresh方法内把配置类解析为Bean定义
springboot启动的时候会生成一个spring上下文ApplicationContext,还会读取全局配置文件等
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {//创建SpringApplication的时候,会把启动类给存储起来return new SpringApplication(primarySources).run(args);}public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");//将启动类存储在primarySourcesthis.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//推算web环境 算法与ConditionOnClass差不多this.webApplicationType = WebApplicationType.deduceFromClasspath();this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();//对外扩展setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//监听器setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();}
refresh之前读取配置类
总结:
1. 获取启动类:根据启动类加载ioc容器
2.获取web应用类型
3.spring.factories读取了对外扩展的ApplicationContextInitializer ,ApplicationListener 对外扩展, 对类解耦(比如全局配置文件、热部署插件)
4. 根据main推算出所在的类
run启动
public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();//控制台打印的时间DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;configureHeadlessProperty();//读取一个listener,发布一个事件//事件多播器,监听者模式SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting(bootstrapContext, this.mainApplicationClass);try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//读取所有的配置文件,通过监听器的方式读取的ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);//创建spring的上下文,会启动内嵌的tomcatcontext = createApplicationContext();context.setApplicationStartup(this.applicationStartup);prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}listeners.started(context);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context;}
