扩展点一些常用的扩展点总结,可能不是完整的,但是基本都在了,有些可能是自定义扩展的,至于这些扩展点怎么用的,可以看我的spring相关文章,基本全部都讲到了。这东西要用的时候可以看看,评估一下用那个合适,基本上扩展点已经按照顺序从上到下排了。注解一些常用注解,springcloud框架有很多自定义的其实也就是这些组合扩展出来的,当然肯定不完整,很多可能不常用的没列出来,有些可能要结合其他框架的,但是基本的一些都在了。启动流程大致的启动流程,知道干了什么事,具体的当然要去看代码啦,还有关键的刷新流程,后面有时间总结下要点。很多事情是初始化器和监听器一起完成的,具体的可以看我写的springboo
基本流程图加载环境配置如果有环境配置会进行处理,然后会加到profiles里,进行环境配置的加载。其实就是这个循环,只要里面还有机会继续加载,所以就不多说了。要注意,这里面可能还有过滤条件要处理。根据profile不同的,有不同的过滤条件。addLoadedPropertySources添加到环境属性源环境配置有限放前面。applyActiveProfiles添加激活配置添加到环境的激活配置中。多激活环境其实你可以配多个激活环境,属性绑定的时候规则还挺复杂的,默认是放后面的环境属性优先,但是属性缺失的话还会去前面的找,有兴趣的自己可以研究下,不过还是别这样做,自己都搞晕。好了,今天就到这里了,
基本流程图application配置文件加载我们考虑简单的application配置文件的加载,其实这个时候只是个名字,后面会进行前后缀的拼接。application配置文件加载接下来就遍历名字集合,然后进行加载,主要是下面这段,其实这里就是获取所有的属性源加载器,比如PropertiesPropertySourceLoader是加载"properties","xml"后缀的,YamlPropertySourceLoader是加载"yml","yaml"后缀的,所以这里就遍历出题目的后缀,然后里面进行路径拼接后尝试
基本流程图Loader的load加载配置文件简单的说其实内部就是加载默认的配置文件,激活环境的文件,我们来看看细节。voidload(){FilteredPropertySource.apply(this.environment,DEFAULT_PROPERTIES,LOAD_FILTERED_PROPERTY,(defaultProperties)->{this.profiles=newLinkedList<>();this.processedProfiles=newLinkedList<>();this.activatedProfiles=false;this
基本流程图配置文件加载原理我们最常用的就是application.yml配置文件,里面有各种配置信息,然后我们可以将他们和我们的配置属性类绑定,然后使用,有关配置文件属性绑定到配置属性类的原理,可以看这篇文章。本篇想讲下配置文件是什么时候加载进来的原理。ConfigFileApplicationListener他属于自动配置里的一个监听器,初始化的时候会进行加载,自动配置原理就不多说了。何时加载配置文件其实是在环境准备好的时候,会有一个ApplicationEnvironmentPreparedEvent事件通知,而ConfigFileApplicationListener就是接受这个通知的,
简单流程ConfigurationPropertiesBindingPostProcessor的postProcessBeforeInitialization初始化之前处理这里就是配置属性绑定的入口了,其实就是个扩展处理器。ConfigurationPropertiesBean的get其实没做什么,就是将实例的一些信息封装成一个ConfigurationPropertiesBean对象,方便后面处理,比如获取工厂方法,然后将名字,实例,注解,绑定对象,封装到ConfigurationPropertiesBean中,这里要注意的就是ConfigurationPropertiesBean中的bin
简单流程@ConfigurationProperties这个是把一个类设置成配置属性,但是要绑定启用,得有个条件,就是得有@EnableConfigurationProperties注解,里面放入要启动的类。例子还是前面的例子,这次就加了ConfigurationProperties注解。然后找了个能注册到容器的配置类,加上EnableConfigurationProperties注解,写上启动的类。这里要注意EnableConfigurationProperties只要挂在能注册到容器的类就可以,没有规定是哪个类,只要里面加上你的配置属性类就可以,比如我这里是MyProperties.cla
@Value(“xxxx”)这个应该基本都用过,直接在属性上用的多,其实方法上也可以用,这个相对简单,先说这个,来个例子,我在name属性上用了,然后在applyName方法上也用了,先不管那到底结果是怎么样呢:结果就是属性上的先被赋值,name是111:然后又进行方法注入赋值,改成了222:QualifierAnnotationAutowireCandidateResolver的getSuggestedValue其实原理就是用了@Value注解的属性和方法都会被AutowiredAnnotationBeanPostProcessor处理进行注入,在注入的过程中,会有一个获取建议值的方法:其实
基本处理流程图自定义全局异常处理首先创建一个异常解析器,实现HandlerExceptionResolver接口即可,这里异常视图是error1。视图文件error1.html:定义一个配置类,实现WebMvcConfigurer接口,覆盖configureHandlerExceptionResolvers方法,把自定义的异常解析器添加进去即可。结果统一了:原理自定义的处理器什么加入的,最后说,我们先看,我们看他是怎么处理的,解析的时候异常解析器就剩一个了,就是我们定义的那个。然后调用了我们的处理方法,得到模型:最后渲染:那么问题来了,其他的解析器去哪里了呢,其实就是异常处理器初始化的时候,现
基本处理流程图自定义异常页面我们自定义一个错误页面吧,比如我想用Thymeleaf来渲染,那得导入这个包,然后我们知道错误错误视图名字叫做error,所以得有这样一个页面,创建一个error.html放在resources/templates/下:内容就是:这些属性哪里来的,debug里看到的,其实是过程当中一步步设置进去的啦,有兴趣你可以跟一下:最终结果:自定义异常处理方法自定义异常增强类,处理方法得有ExceptionHandler注解,注解属性里面也可以定义异常类型,不过这个只能用于HandlerMethod处理:处理方法:my_error.html:为什么只能用于HandlerMeth
基本处理流程图继续抛异常继续上篇的,异常没法被异常解析器处理,继续抛出:拦截器处理完后继续抛出:FrameworkServlet封装成嵌套的NestedServletException继续抛:不过下面会打印信息:内部会打印:一路抛到org.apache.catalina.core.StandardWrapperValve的invoke,输出异常信息,用exception方法处理响应设置:设置响应状设置错误状态errorState=1。然后继续执行:最后到这里找到默认的报错页面:然后一通属性请求和响应设置之后到这里:内部然后进行转发到/err.然后请求又进来,要分发了,这个请求最后被BasicE
基本处理流程图通常的异常处理我们来演示下,看看通常异常是怎么处理的,我们什么都不加,只是这样,看看内部怎么处理的:运行:运行到这里的时候直接抛异常:doDispatch方法中会保存异常。然后处理结果:走有异常的逻辑:进行异常解析器解析,DefaultErrorAttributes只是添加了异常属性,什么都没做:而HandlerExceptionResolverComposite是一个异常解析器的符合解析器,里面有解析器处理。是否能解析异常ExceptionHandlerExceptionResolver的shouldApplyTo一般只解析HandlerMethod处理器类型的异常,刚好我们就
BeanNameUrlHandlerMapping是什么其实这个就是在用bean注解方法的时候填写的名字作为uri和bean处理器映射。先看例子,比如我定义了两种老的写法的处理器:然后我在配置文件中注入他们,都命名了:然后访问:好像也挺方便哦,但是都要实现接口,而且方法参数是死的,无法做到直接获取需要的参数值,而ResourceHttpRequestHandler更强大,他可以任意传参数,只要能匹配的上都可以匹配,等于定制化,灵活,你可以实现任何你想要的参数类型,只要你编写解析器。我们来说说原理吧。BeanNameUrlHandlerMapping初始化他也是EnableWebMvcConfi
获取资源@NullableprotectedResourcegetResource(HttpServletRequestrequest)throwsIOException{Stringpath=(String)request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);//获取前面放入的路径属性...path=processPath(path);//处理路径,获取资源名字...Resourceresource=this.resolverChain.resolveResource(request,path,
静态资源如何访问可以直接访问静态资源,因为有SimpleUrlHandlerMapping处理。EnableWebMvcConfiguration的resourceHandlerMapping自动配置EnableWebMvcConfiguration的resourceHandlerMapping调用的时候:ResourceHandlerRegistry的resourceHandlerMapping最后创建一个SimpleUrlHandlerMapping,里面有两个映射,定义了两种资源路径:然后在他在初始化之前处理的setApplicationContext方法中注册了两个映射:注册到hand
验证请求参数跟类方法匹配我把Dog类方法的一些属性名改了:继续按方法的名字去掉前缀发送:结果可以:那我把方法名字改下,后面都加1:结果这两个参数没绑定:结论参数绑定跟方法的匹配,而且需要有set方法。比如setBirth,参数名字可以是Birth或者birth。CachedIntrospectionResults构造方法里会进行设置。判断可不可写的时候会获取:获取到之后会进行封装,封装成BeanPropertyHandler:是否可读可写就是看有没有读方法和写方法:所以说这里属性是否可被绑定是跟属性set方法名字相关的,有兴趣的朋友可以调试下,里面还是比较深的。绑定参数名字修改完后就是这个样子
基本流程图bindRequestParameters绑定请求参数如果不是禁止绑定的话,就要进行请求参数的绑定,禁止绑定就是ModelAttribute注解里的binding属性。bindRequestParameters绑定请求参数我们直接深入里面的核心方法,其他的以前讲过。doBind准备绑定这里参数也准备好了,就是请求参数,包括了表单和uri的。@OverrideprotectedvoiddoBind(MutablePropertyValuesmpvs){checkFieldDefaults(mpvs);checkFieldMarkers(mpvs);super.doBind(mpvs);
基本流程图数据绑定前面说了模型方法调用,里面涉及数据转换和数据绑定,但是这里我准备用一个处理器方法来说数据绑定,比较好理解点。请求信息:绑定方法:进行数据绑定我们就拿第一个参数Dog来说,前面会进行属性的创建,一个空的Dog对象,准备进行绑定。其实绑定的规则就是绑定方法设置的,然后绑定的数据就是来源于请求参数里的参数。我们来看看吧,里面很深哦。创建和初始化WebDataBinder这里已经讲过了,主要是初始化,他会进行所有绑定方法的匹配,匹配的就执行绑定方法,添加绑定规则。先看执行前:绑定方法匹配,刚好绑定方法里的名字里有dog,和我们的属性名字匹配,我们的方法参数前没加ModelAttrib
数据转换convertIfNecessary一路调用内部最后到这里:最后抛异常了:这里明显会转换错误,我故意的,如果是数字的话肯定是没问题的。这下次我改改:有了:请求参数不存在的情况createAttribute前面分析的都是请求参数存在了,如果不存在呢,其实就是用构造方法创建一个对象。protectedObjectcreateAttribute(StringattributeName,MethodParameterparameter,WebDataBinderFactorybinderFactory,NativeWebRequestwebRequest)throwsException{Met
createAttributeFromRequestValue上篇说道,我们从请求参数里获得了属性值,但是是String类型的,而我们的参数需要是int的,所以这里会有一个绑定和转换的过程,我们来看看是怎么做的。数据绑定器初始化在创建数据绑定器WebDataBinder后,会进行初始化,也就是让数据绑定工厂的所有绑定方法来执行一遍,因为绑定方法那么多,不知道哪个是可以绑定上的,所以要遍历执行,先看能不能满足条件,满足条件的话就执行绑定方法,所以这里如果有很多的话,也不太会有太大的性能问题,因为可能只有一个能绑定上,甚至没有,只是会判断绑定的条件是否符合isBinderMethodApplica
模型方法是什么就是我们用ModelAttribute注解的方法,比如:模型方法返回值作为属性放进了模型内先获得返回值,获取属性名字,就是ModelAttribute注解里的名字,如果没有就是返回值类型名字的首字母小写当做名字,这个好像前面讲过,都是这个规则。我这里设置了名字@ModelAttribute("name")。模型方法参数中的Model其实就是模型容器里的BindingAwareModelMap如果我们的模型方法里有Model参数的话,参数解析器ModelMethodProcessor就会返回模型容器里的模型BindingAwareModelMap对象,他是Mod
执行链结构图拦截器哪里来的执行链前面讲过,但是没细讲,我们先来看他是怎么形成的。首先是在EnableWebMvcConfiguration的父类WebMvcConfigurationSupport的getInterceptors里面会添加自定义的拦截器,然后再加入两个拦截器:这些拦截器干嘛的MyHandlerInterceptor自定义的只是输出信息。ConversionServiceExposingInterceptor设置请求的转换服务,这个后面跟数据绑定相关,到时候会说的。ResourceUrlProviderExposingInterceptor设置静态资源url提供器,让客户端可以访
处理大致流程图DispatcherServlet的processDispatchResult前面讲了处理器适配求怎么处理请求返回结果的,现在讲结果怎么处理,其实核心就是render方法。privatevoidprocessDispatchResult(HttpServletRequestrequest,HttpServletResponseresponse,@NullableHandlerExecutionChainmappedHandler,@NullableModelAndViewmv,@NullableExceptionexception)throwsException{...//Did
处理大致流程图ModelFactory的findSessionAttributeArguments寻找session属性参数值前面花了大篇幅讲模型方法的触发,也就是说在正式调用处理器之前,先调用模型方法,就是有ModelAttribute注解的方法,可以给模型添加参数,里面的参数解析和数据绑定也讲了点,但是只是凤毛菱角,后期还是需要再去看的,今天开始继续讲,不然深入细节就没完没了了。这段代码就是获取方法类上的SessionAttributes注解的名字的,只要你的方法参数里有ModelAttribute注解,且注解的名字和类上的相同,就返回。如果这个属性值不存在的话,就会去获取,然后放入模型里
处理大致流程图DefaultDataBinderFactory的createBinder如果没有异常的话,就要创建WebDataBinder,进行数据绑定,这里的关键在initBinder中。@Override@SuppressWarnings("deprecation")publicfinalWebDataBindercreateBinder(NativeWebRequestwebRequest,@NullableObjecttarget,StringobjectName)throwsException{//创建数据绑定WebDataBinderdataBinder=cr
处理大致流程图如何匹配参数supportsParameter参数解析器有那么多,暂时不可能全部都讲,说几个比较常用的,来看看他们是怎么匹配参数的。PathVariableMethodArgumentResolver这个就是匹配PathVariable注解的。@OverridepublicbooleansupportsParameter(MethodParameterparameter){if(!parameter.hasParameterAnnotation(PathVariable.class)){returnfalse;}if(Map.class.isAssignableFrom(para
处理大致流程图ModelFactory的initModel初始化模型前面数据绑定工厂和模型工厂都创建好了,现在我们要进行模型初始化了。其实就是将session里的属性和并到模型,然后调用模型方法,获取注解的参数的值放入模型里,说白了就是先处理模型方法,然后把属性放入模型。publicvoidinitModel(NativeWebRequestrequest,ModelAndViewContainercontainer,HandlerMethodhandlerMethod)throwsException{//获取session属性Map<String,?>sessionAttribu
处理大致流程图getDataBinderFactory其实就是先获取方法所在的类,看缓存里有没有相关方法,没有就找出有InitBinder注解的方法放入缓存,然后再处理全局的绑定增强方法,有的话也要加入绑定集合,最后将绑定方法集合封装成WebDataBinderFactory返回。privateWebDataBinderFactorygetDataBinderFactory(HandlerMethodhandlerMethod)throwsException{Class<?>handlerType=handlerMethod.getBeanType();//方法的处理器类型Set&
处理大致流程图getDataBinderFactory获取数据绑定工厂这个是什么东西,数据绑定,要干嘛呢,其实就是参数的绑定啦,一般的基本都能处理,比如我传个对象。接受一个对象接受多个对象但是如果我想要传两个呢,当然你可以说可以封装成一个对象呀,是可以,我这里就想说,如果是两个会怎么样:两个一起赋值了。解决办法这个时候可以用到数据绑定,也就是说,我希望某个属性你给我绑定到某个对象的属性上,比如我这样把他们分开:但是springmvc是不知道的:那这个时候就需要告诉他,这些数据怎么跟我的方法参数绑定起来,就要用到@InitBinder啦,比如我定义两个方法来做绑定,d.开头的都要给Dog类,c.
处理大致流程图获取处理器适配器适配器模式为什么要处理器适配器,我们前面不是获取处理器方法了么,直接调用就好啦。对没错,但是那可能只是一种处理器的方式,也就是HandlerMethod,以前还有另外的方式哦,比如实现Controller接口的:还有实现HttpRequestHandler接口的:他们的接口都不一样,总得兼容吧,处理接口不一致的办法不就是适配器模式嘛,你接口不同,我用不同的适配器来适配,对外都是统一接口,如果以后有新的实现,我只要添加适配器即可,这里就是适配器模式的应用啦。DispatcherServlet的getHandlerAdapter这里就是遍历所有的处理器适配器,看哪个是