@SpringBootApplication给我做了些什么:
这个注解的子注解有
@SpringBootConfiguration:表示这个是一个配置类
@ComponentScan:指定扫描哪些spring注解(controller、service。。。)
@EnableAutoConfiguration:
@AutoConfigurationPackage:自动配置了扫描哪个包,默认是MainApplication启动类所在的包
@Import(AutoConfigurationImportSelector.class):给容器中批量导入一些组件,这些组件是写死的127个,springboot一启动就会将这些组件全部加载,但是并不会全部装配,而是按需装配。比如说某个依赖没有导入,说明不需要用到这一块的的内容,所以与这个内容相关的组件就不需要装配了。
每一个组件中的值都是在xxxproperties里面拿,而每一个xxxproperties都是和配置文件绑定的,所以如果想要修改默认的组件属性只需要到配置文件中修改件就可以了。
其中dispatcherServlet就是在springboot启动的时候自动帮我们装配并且设置好了。
如果想要定制化配置的话有两种方法:
- 用户在配置类中自己写@Bean替换底层组件
- 这个组件的值都是在xxxProperties中拿的,可以在application.properties中修改对应属性的值
Rest风格
/user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户
核心Filter:HiddenHttpMethodFilter
用法: 表单method=post,隐藏域 _method=put SpringBoot中需要手动开启
在form表单中填写_method属性
表单提交要使用REST风格的时候的原理:
表单提交的时候会带上属性_method=POST
请求被HiddenHttpMethodFilter拦截
Filter判断请求是否是POST请求
获取到_method的值
能兼容的_method的值有PUT,DELETE,PATCH
new了一个HttpMethodRequestWrapper对象,这个类是使用装饰模式对原生Request的装饰,这个类重写了getMethod方法,返回的是传入的_method的值
FilterChain放行的时候用wrapper代替了原生request,以后方法调用getMethod是调用wrapper的。
Springtboot的启动过程:
1创建SpringAplication(保存一些信息)
1、用ClassUtils判断是响应式编程还是servlet,servlet编程的话会return WebApplicationType.SERVLET
2、bootstrappers:初始启动引导器:去spring.factories文件中找所有 org.springframework.boot.Bootstrapper封装成List<Bootstrapper>
3、找 ApplicationContextInitializer:去spring.factories找 ApplicationContextInitializer
List<ApplicationContextInitializer<?>> initializers
4、找 ApplicationListener :应用监听器。去spring.factories找 ApplicationListener List<ApplicationListener<?>> listeners
5、最后通过找哪个类中有main方法来决定哪个类是主程序。
2运行SpringApplication
1、stopWatch.start();记录应用启动时间
2、创建引导上下文(Context环境)createBootstrapContext()
获取到所有之前的 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置
3、让当前应用进入headless模式。java.awt.headless(自力更生)
4、获取所有 RunListener(运行监听器)【为了方便所有Listener进行事件感知】去spring.factories找 SpringApplicationRunListener.
遍历 SpringApplicationRunListener 调用 starting 方法;
相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting。
5、保存命令行参数:ApplicationArguments
6、准备环境:
1根据webApplicationType返回或者创建环境信息:
return new StandardServletEnvironment();
2配置环境信息对象:configureEnvironment(environment, applicationArguments.getSourceArgs());读取所有的配置源的配置属性值。
3绑定环境信息:ConfigurationPropertySources.attach(environment);
4监听器调用: listener.environmentPrepared();通知所有的监听器当前环境准备完成:
listeners.environmentPrepared(bootstrapContext, environment);
7、创建IOC容器:context = createApplicationContext();
还是根据webApplicationType类型创建:return new AnnotationConfigServletWebServerApplicationContext();
8、准备IOC容器:
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
1、保存环境信息:context.setEnvironment(environment);
2、处理IOC容器的后置处理流程:
postProcessApplicationContext(context);
3、应用初始化器:applyInitializers(context);
1遍历所有的 ApplicationContextInitializer 。调用 initialize.。来对ioc容器进行初始化扩展功能
2遍历所有的 listener 调用 contextPrepared。EventPublishRunListenr;通知所有的监听器contextPrepared
listeners.contextPrepared(context);
4、遍历所有监听器 调用 contextLoaded。通知所有的监听器 contextLoaded;listeners.contextLoaded(context);
9、刷新IOC容器。refreshContext
1创建容器中的所有组件(参考Spring注解版)
2容器刷新完成后工作?afterRefresh()
3所有监听 器 调用 listeners.started(context); 通知所有的监听器 started
4调用所有runners;callRunners()
获取容器中的 ApplicationRunner
获取容器中的 CommandLineRunner
合并所有runner并且按照@Order进行排序
遍历所有的runner。调用 run 方法
5如果以上有异常,
调用Listener 的 failed
6调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 running
7running如果有问题。继续通知 failed 。调用所有 Listener 的 failed;通知所有的监听器 failed