springboot
@Configuration(proxyBeanMethods = true/false) 代理bean的方法--管理组件依赖 proxyBeanMethods = true Full模式(全模式) 加载速度慢 full模式 该模式下,配置类会被CGLIB增强(生成代理对象),放进IoC容器内的是代理 该模式下,对于内部类是没有限制的:可以是Full模式或者Lite模式 该模式下,配置类内部可以通过方法调用来处理依赖,并且能够保证是同一个实例,都指向IoC内的那个单例 该模式下,@Bean方法不能被private/final等进行修饰,因为代理类需要重写这个方法 proxyBeanMethods = false Lite模式(轻量级模式) 加载速度快 lite模式 1.该模式下,配置类本身不会被CGLIB增强,放进IoC容器内的就是类本身 2. 该模式下,对于内部类是没有限制的:可以是Full模式或者Lite模式 3. 该模式下,配置类内部不能通过方法调用来处理依赖,否则每次生成的都是一个新实例而并非IoC容器内的单例 4. 该模式下,配置类就是一普通类,所以@Bean方法可以使用private/final等进行修饰
@import的三种用法主要包括: --导入bean到容器中,配合@Configuration注解使用,必须要有无参构造器
1、直接填class数组方式
2、importSelector方式【重点】
3、importBeanDefinitionRegistrar方式
第一种用法:@import({ 要导入到容器中的组件 } ):容器会自动注册这个组件,id默认是全类名
第二种用法:importSelector:返回需要导入的组件的全类名数组,springboot底层用的特别多【重点】
第三种用法:importBeanDefinitionRegistrar:手动注册bean到容器
@Conditional Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean,配合@Configuration注解使用
@importResource 导入spring.xml配置文件到容器中,配合@Configuration注解使用
@Component + @ConfigurationProperties(prefix="") @EnableConfigurationProperties + @ConfigurationProperties(prefix="")
@SpringBootConfiguration @import(AutoConfigurationimportSelector)
Springboot自动装配原理
通过@SpringBootApplication复合注解内部的@EnableAutoConfiguration注解实现的自动装配,该注解内部的@import(AutoConfigurationimportSelector)注解,通过SpringFactoriesLoader加载auto-configurer模块里meta-INF下的spring.factories文件,获取一个key为EnableAutoConfiguration的全类名,值为AutoConfiguration自动配置类全类名列表的属性,然后让@import注解导入这些配置类,其中满足@Conditional相关注解条件的组件会被注册进容器中.组件的属性值则是通过@EnableConfigurationProperties注解引入对应的properties配置类,而properties配置类通过@ConfigurationProperties注解绑定对应前缀的配置文件属性,从而给组件设置属性值,以此来实现自动装配
Springboot静态资源配置
spring:
mvc:
static-path-pattern: /res/** #配置静态资源访问映射路径,默认/**
web:
resources:
static-locations: classpath:/zz/ #配置静态资源位置,默认/meta-INF/resources/, /resources/,/static/,/public/(4个位置),可通过static-locations: classpath:/xx/ 自定义设置location
欢迎页index.html和favicon.ico图标可以配置静态资源路径,不可以配置静态资源访问前缀,否则失效
addResourceHandlers 添加静态资源映射,有三个,分别是webjars,static-path-pattern,static-resources
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/meta-INF/resources/")
}
表单页面开启rest请求功能
spring:
mvc:
hiddenmethod:
filter:
enabled: true #开启页面表单的Rest功能
隐藏请求方式过滤器代码解析:
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
HttpServletRequest requestToUse = request;
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
String paramValue = request.getParameter(this.methodParam); //获取_method参数值
if (StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
if (ALLOWED_METHODS.contains(method)) {
requestToUse = new HttpMethodRequestWrapper(request, method);
}
}
}
filterChain.doFilter(requestToUse, response);
}
servlet请求
Servlet -> GenericServlet -> HttpServlet
Servlet接口包括init getServletConfig service getServletInfo destroy五个方法
GenericServlet抽象类实现获取servlet上下文,获取initParameter等通用方法,三个生命周期方法没实现
HttpServlet抽象类实现了service()方法,根据请求方式分发到具体的doxxx实现
springmvc请求
springmvc在servlet的基础上扩展了三个类
HttpServlet -> HttpServletBean -> frameworkServlet -> DispatcherServlet
servlet初始化 HttpServletBean重写GenericServlet的init()方法,frameworkServlet重写initServletBean()方法,DispatcherServlet重写onRefresh()方法,onRefresh()方法调用initStrategies()方法给mvc容器初始化九大组件
servlet处理请求 frameworkServlet重写HttpServlet的service()、doxxx()方法,调用processRequest()方法,调用doService()方法,DispatcherServlet重写doService()方法,调用doDispatcher()方法,doDispatcher()方法根据请求获取对应的handlerMapping,handlerMapping找到对应handlerAdapter,handlerAdapter处理请求,返回modelAndView,调用processDispatchResult()方法渲染页面
doDispatch()解析
HandlerMapping -> AbstractHandlerMapping -> AbstractHandlerMethodMapping -> RequestMappingInfoHandlerMapping -> RequestMappingHandlerMapping
doDispatch() -> getHandler() -> getHandlerInternal() -> lookupHandlerMethod() -> addMatchingMappings() -> getMatchingMapping() -> getMatchingCondition() -> matchRequestMethod()
根据请求路径去pathLookup里找到RequestMappingInfo列表,遍历查找条件匹配的RequestMappingInfo,主要比较getMethods().equals(requestMethod) ,返回一个RequestMethodsRequestCondition,比较pattern.equals(lookupPath),返回一个PatternsRequestCondition
将它与别的一些匹配的条件封装成一个新的RequestMappingInfo,然后将新的RequestMappingInfo和当前遍历的RequestMappingInfo对应的MappingRegistration作为参数封装到一个match中,同时返回match里的mappingRegistration里的handlerMethod,然后将handlerMethod赋值给Object类型的handler,生成一个HandlerExecutionChain,通过它里面的Object handler的类型去遍历寻找支持对应的HandlerAdapter,最后HandlerAdapter通过遍历调用参数解析器解析对应的参数,通过web数据绑定器里的转换器将参数转换成目标类型,通过反射调用目标方法,并将解析后得到的object[]参数传递进去,得到返回值, 然后对应的返回值处理器会对返回值进行处理,处理器会对ModelAndViewContainer中的requestHandled或view进行不同的设置,然后进行内容协商,保证服务器可生产类型与客户端可接收类型兼容,再通过对应的消息转换器MappingJackson2HttpMessageConverter将消息转换成协商后的mediaType,响应给客户端,后续再通过判断ModelAndViewContainer中的requestHandled状态,来判断是否生成对应的ModelAndView,如果为true,则返回null,如果为false,则生成ModelAndView,之后再调用对应视图解析器里的模板引擎对其进行process渲染处理
其实它的映射关系都注册好了:RequestMappingHandlerMapping里有个mappingRegistry属性,这个属性包含了一个registry的hashMap属性,这个hashMap中的key是RequestMappingInfo类型的数据,它里面的patternsCondition和methodsCondition分别保存着请求路径和请求方式,value是MappingRegistration类型的数据,它里面有个handlerMethod属性,这个handlerMethod里面的beanType和method属性分别保存着处理类的全类名和处理方法的名字
org.springframework.web.servlet.HandlerMapping.bestMatchingHandler handlerMethod
org.springframework.web.servlet.HandlerMapping.pathWithinHandlerMapping lookupPath
SpringBoot默认配置了多个HandlerMapping
-
RequestMappingHandlerMapping
-
WelcomePageHandlerMapping
SpringBoot基本注解
@PathVariable 获取路径变量
@RequestHeader 获取请求头
@RequestParam 获取请求参数
@cookievalue 获取请求头的cookie值
@RequestBody 获取Post请求的请求体
@RequestAttribute 获取request域属性
@MatrixVariable 获取矩阵变量
cookie 和session 的区别:
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗
考虑到安全应当使用session。3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,应当使用cookie。4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
5、所以个人建议:
将登陆信息等重要信息存放为SESSION
其他信息如果需要保留,可以放在cookie中
Map Model ModelMap 在页面转发时被解析成BindingAwareModelMap
自定义类型接收参数 由ServletModelAttributeMethodProcess解析器解析,将请求参数类型通过反射创建一个空的对象,然后通过数据绑定器将请求中的参数值先通过转换器转换成目标类型,然后绑定到target对象上,最后通过反射调用目标方法,将绑定后的对象作为参数传递进去
需要binder中的converter转换请求参数的注解
@matrixVariable
@RequestParam
@PathVariable
@RequestBody
自定义类型参数
加了@ResponseBody注解,返回值被RequestResponseBodyMethodProcessor处理,将ModelAndViewContainer里的RequestHandled状态改为true,然后进行内容协商,确定服务器可生产类型与浏览器可接收类型兼容,通过对应的消息转换器MappingJackson2HttpMessageConverter将消息转化成对应的mediaType,响应给客户端,并没有设置viewName,消息处理后续也不会渲染,
没加@ResponseBody注解,返回值被ViewNameMethodReturnValueHandler处理,将返回值作为viewName设置到ModelAndViewContainer中
ContentNegotiationManager内容协商管理器
默认使用基于请求头的策略HeaderContentNegotiationStrategy,就是获取请求头Accept里的mediaType
此外还有基于请求参数的策略ParameterContentNegotiationStrategy,就是根据format参数找到mediaType
给springmvc定制什么功能,都是通过实现WebMvcConfigurer接口实现
Thymeleaf自动配置类主要配置了SpringTemplateEngine和ThymeleafViewResolver
先导入名称空间xmlns:th="http://www.thymeleaf.org"
文本用th:text标签,request请求域用${}
1.过滤器依赖于servlet容器,只能用于web程序,拦截器依赖于spring容器,还可以用于Application程序
2.过滤器基于函数回调实现,拦截器基于反射实现,属于aop的一种运用
3.过滤器可以过滤所有访问sevlet容器的请求,拦截器只能拦截访问controller的请求
4.过滤器只能在初始化时被调用一次,拦截器可以被多次调用
先执行所有preHandle,如果有任一返回false,则执行triggerAfterCompletion,根据当前interceptorIndex倒叙执行拦截器的afterCompletion的方法,如果拦截验证都通过,则执行目标方法,再执行postHandler,再执行渲染页面,再执行afterCompletion
文件上传解析器
容器先自动配置StandardServletMultipartResolver(标准Servlet文件上传解析器)
先判断是不是文件上传请求,如果是,通过StandardServletMultipartResolver解析器将HttpServletReuqest请求封装成StandardMultipartHttpServletRequest,接着用RequestPartMethodArgumentResolver解析请求参数,将文件参数封装成StandardMultipartFile
异常处理
DefaultErrorAttributes将异常设置到request域中,并返回null
首先用dispatchException捕获到异常,传到processDispatchResult里,遍历异常解析器列表解析异常,通常DefaultErrorAttributes并不会处理异常,只是将异常信息记录到request域中,剩下的异常解析器集合中,一个是处理@ExceptionHandler注解标记的异常,通过反射调用我们自定义的异常处理方法,最后两个异常解析器,一个是处理@ResponseStatus注解标记的异常,一个是处理springmvc默认的15个异常类型,它们都是获取到异常状态码和异常信息,传入到reponse.sendError(code,mesage)方法中,最终调用tomcat的StandardHostValue里的custom()转发/error请求,由BasicErrorController接收处理,先去template模板的error目录下找这个错误状态对应的html,如果没有找到,就去4个静态资源路径下找error目录下对应错误状态的html,如果静态资源也没有找到,就根据HttpStatus里series枚举类是Client_Error还是Server_Error,去template模板下找4xx.html或5xx.html,如果还是没有,就响应tomcat原生的错误页
Web三大组件(Servlet 、Filter 、Listener)
1.注解添加组件
@WebServlet(urlPatterns = “”) + extends HttpServlet
@WebFilter(urlPatterns = “”) + implements Filter
@WebListener + implements ServletContextListener
@ServletComponentScan(basePackages = “”)
2.RegistrationBean配置类添加组件
ServletRegistrationBean
FilterRegistrationBean
ServletListenerRegistrationBean
@EnableWebMvc
全面替换SpringMvc默认配置,慎用
mysql Connector/J 8.0.15及以上只支持 mysql5.6 mysql5.7 mysql8.0
mysql Connector/J 6.x及以上需要使用jdbc驱动com.mysql.cj.jdbc.Driver
druid数据源配置
druid:
filters: stat,wall
aop-patterns: com.atguigu.admin.*
stat-view-servlet:
enabled: true
login-username: admin123
login-password: admin123
web-stat-filter:
enabled: true
filter:
stat:
slow-sql-millis: 1
log-slow-sql: true
enabled: true
mybatis配置
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
type-aliases-package: com.xxx
configuration:
map-underscore-to-camel-case: true
SpringBoot2.4以后JUnit默认移除vintage引擎,只有Jupiter引擎
@Autowired/@Resource/@Transactional
SpringBoot启动流程
启动流程就是创建SpringApplication实例并执行run方法,
创建SpringApplication主要是判断设置webApplicationType,加载meta-INFspring.factories文件下的接口实现类列表,设置bootstrapRegistryInitializers和ApplicationContextInitializer和ApplicationListener,推断MainApplication的Class
执行run方法,首先是创建stopWatch记录应用的启动时间,创建引导上下文bootstrapContext并初始化,配置HeadlessProperty,加载meta-INFspring.factories文件下SpringApplicationRunListener的实现类(应用运行时监听器),封装成SpringApplicationRunListeners并通知监听器应用正在(starting),将命令行参数封装成ApplicationArguments,接着准备环境Environment,配置属性信息,通知监听器应用环境准备完成(environmentPrepared),打印Banner信息,创建applicationContext,并给context设置environment,遍历初始化器对applicationContext进行初始化,通知监听器应用上下文准备完成(contextPrepared),给applicationContext的beanFactory添加单例bean,包括命令行参数,Banner,通知监听器应用上下文加载完成(contextLoaded),然后刷新应用上下文,通知监听器应用上下文启动完成(started),调用容器中所有的ApplicationRunner和CommandLineRunner,通知监听器应用上下文正在运行(running),如果启动过程出现异常,通知监听器应用上下文启动失败(failed)
starting(ApplicationStartingEvent)-> environmentPrepared(ApplicationEnvironmentPreparedEvent) -> contextPrepared(ApplicationContextInitializedEvent) -> contextLoaded(ApplicationPreparedEvent) -> started(ApplicationStartedEvent) -> running(ApplicationReadyEvent) -> failed(ApplicationFailedEvent)
应用启动各阶段事件发布对应的监听器数量 3 6 2 4 2 5 2
ApplicationEventPublisher.publishEvent() -> AbstractApplicationContext.multicastEvent() -> SimpleApplicationEventMulticaster.multicastEvent() -> invokeListener() -> doInvokeListener() -> ApplicationListener.onApplicationEvent()



