SpringBoot原理分析总结
自动配置特性
每一个starter场景jar包都依赖于spring-boot-starter包,而这个包内部又依赖于一个关键的自动配置包 spring-boot-autoconfiguration 这个里面有所有场景的自动配置类
*autoconfiguration的类名就是,我们pom里面导入了什么场景启动器,这个自动配置包 spring-boot-autoconfiguration 就能启用对应的自动配置包,按需加载
认识springboot特有的注解
@Configuration:代替xml配置文件,用java代码的方式给容器注册bean对象,只需要加上@bean注解即可
@Configuration(proxyBeanMethods = false) 表示取消默认的单例模式
@Import({User.class, DBHelper.class}) 给容器中自动创建出这两个类型的组件
@Conditional条件装配:满足才生效
@ConditionalOnBean(name = “tom”) 是否有tom组件,有则满足条件,则执行代码
@ImportResource 导入设置好的xml文件
@ConfigurationProperties 配置绑定 类似数据库连接封装到bean对象
自动配置源码分析
主启动类上的@SpringBootApplication注解内部主要是由三个主要注解组成的,@EnableAutoConfiguration,@SpringBootConfiguration,@ComponentScan。
@SpringBootConfiguration里面就是@Configuration,表示是作为一个配置类
@ComponentScan表示指定扫描哪些Spring注解
最关键的就是@EnableAutoConfiguration: 里面含有两个关键注解
@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)
@AutoConfigurationPackage 是自动配置包,里面有一个@Import注解,Import注解的作用是向容器导入指定的类对象,而这里的import里面导入的是Refistrar.class,这里的Registar其实是一个class数组,里面先获取了启动类的包路径,然后再把包路径下的类都放在Registar数组内,这样就可以实现把包路径的组件都引入容器中
@Import(AutoConfigurationImportSelector.class)这个注解里面的class对象里面主要有一个关键方法getAutoConfigurationEntry是给容器批量导入一些组件的,而这里面有一个关键方法是getCandidateConfigurations,这个方法内部利用了工厂加载,loadSpringFactories是默认扫描在项目的所有META-INF/spring.factories
而里面的autoconfigure包下也有这个spring.factories文件,里面包含了127种不同场景下的自动配置类,等于说一启动项目,这127个配置类就会被加载
但是springboot有条件装配规则注解**@Conditional**,实现按需配置,在pom内加入的starter场景包,对应的xxxautoConfiguration类才会生效。
生效的配置类就会给容器种装配很多组件,只要组件注入容器,相当于功能就有了。
每个自动配置类都有一个绑定properties的注解,我们可以通过ctrl进入源码查看里面的prefix字段,然后在application.xml中编写对应的参数,实现自定义配置,例如Tomcat组件的端口号
静态资源源码分析总结
SpringMVC功能的自动配置类WebMvcAutoConfiguration里面的条件注解满足,生效。
这个自动配置类有一个WebMvcAutoConfigurationAdapter类,这个类的有参构造器的参数很多是利用了properties,也就是绑定了很多配置文件。
这个WebMvcAutoConfiguration配置类里面还拥有一个主要方法addResourceHandlers是资源处理的默认规则,先判断有没有被禁用默认规则,没有则往下找,默认是**/webjars/路径**,然后会在ResourceProperties配置文件中找路径,里面设置了默认的资源路径。
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS =
{ "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
/**
* Locations of static resources. Defaults to classpath:[/META-INF/resources/,
* /resources/, /static/, /public/].
*/
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
...
}
对于默认访问资源路径下的index.html的配置方法,也在WebMvcAutoConfiguration内,是WelcomePageHandlerMapping,这是个bean对象,是一个处理器映射器,
WelcomePageHandlerMapping的构造方法里面写死了是欢迎页是index.html
REST映射使用和源码分析
表单发送delete和put请求,需要设置method为post,然后加入隐藏行<input name="_method" type=“hidden” value=“PUT/DELETE” />,然后在application.xml中设置hiddenmethod.filter.enable为true,因为默认是false关闭。
原理是 开启了这个filter拦截器,请求过来就被HiddenHttpMethodFilter拦截,判断是否 是POST请求,是的话会去获取里面的key为\method的value值,然后会对参数转为大写字母,判断这个请求方式是否兼容(PUT.DELETE.PATCH) ,兼容的话,就会使用包装模式requesWrapper重写了getmethod方法,然后doFitler放出warpper,后面处理请求的就变成了被包装的wrapper类。
请求处理源码分析
请求过来,进入DispathcerServlet的doDispatcher方法,先遍历所有的HandleMapping挨个尝试看是否有请求信息,找到RequestMappingHandleMapping,这个处理器映射器保存了我们controller里面设置的所有@RequestMapping映射规则,通过传入的请求参数路径,就可以找到对应的controller方法。
然后遍历所有的处理器适配器为当前Handler 找一个适配器 HandlerAdapter,用的最多的是RequestMappingHandlerAdapter。进入适配器就会执行目标方法并确定方法参数的每一个值。
参数解析部分:
(参数确定使用了遍历内部的26个参数解析器argumentResolvers来尝试解析。
大致有4种参数类型:Servlet API参数,model,map类型,注解参数类型,类对象
特殊的API例如SerlvetRequest HttpSession参数等,内部有特殊的一个参数解析器ServletRequestMethodArgumentResolver来解析
map、model里面的数据会被放在request的请求域 request.setAttribute,原理是:
map,model这两个参数类型分别会被26个参数解析器中的MapMethodProcessor和ModelMethodProcessor解析,处理后都会返回存入mavContainer.getModel()
自定义类对象参数也能自动封装成对象,原理是:
自定义参数会被ServletModelAttributeMethodProcessor解析器解析,选中的逻辑是判断是否是简单类型。 先创建一个空自定义类对象,然后利用的是WebDataBinder 数据绑定器,里面的转换服务利用了127个Converters 转换器(参数的类型都是String字符串,而对象的属性可能是其他类型需要转换,例如int,float等),实现对request里面的参数都绑定封装到创建的自定义对象里面)
参数准备完成后就执行业务方法,直到返回页面结果的时候,把方法的返回值类型保存到mavContainer里面,里面还有model数据和view视图,然后会把mavContainer 封装成ModelAndView对象
响应数据源码分析
前后端分离项目一般使用响应数据的形式
给前端自动返回json数据,需要引入json的场景starter包
遍历15个ReturnValueHandler返回值处理器,通过获取到的返回值类型判断,@ResponseBody注解找到返回值处理器RequestResponseBodyMethodProcessor
这个处理器内部是利用MessageConverters消息类型转换器进行处理,通过内容协商(服务器能发生什么样的内容类型,客户端Accept请求行能接收什么样的内容类型),挨个遍历所有容器底层的HttpMessageConverter ,用支持将对象转为最佳匹配媒体类型的converter最后将数据转换为json数据
响应页面源码分析
对于返回值为“list”页面的业务方法,在返回值之前的执行流程和上面是一致的。然后会拿到返回值内容,然后遍历寻找可以解析的返回值处理器ViewNameMethodReturnValueHandler,这里面首先会把返回值内容放在mavContainer里面,任何目标方法执行完成以后都会返回ModelAndView(数据和视图地址)。之后会执行processDispatchResult()处理派发结果,里面有一个方法render进行页面渲染,先遍历所有视图解析器ViewResolvers按照内容协商得到最佳的为RedirectResolvers,这个视图解析器内部的操作流程是先获取目标url,然后response.sendRedirect(encodedURL);
拦截器原理
根据当前请求,找到HandlerExecutionChain这是这个方法对应的拦截器链,然后后面会调用preHandle()对拦截器链进行顺序执行所有拦截器的preHandle方法,如果有一个失败,则从当前节点往前倒叙执行postHandler,只有所有拦截器都返回true,执行完毕后才往下执行目标方法。