Spring Boot注解的原理(含有自动配置原理)

@SpringBootApplication注解

由以下几个组件组成:

@SpringBootConfiguration(和configuration的作用一样并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中

@EnableAutoConfiguration开启自动配置--该注解中有一个@Import(AutoConfigurationImportSelector.class),而其中发挥自动配置作用就是AutoConfigurationImportSelector类。

观察AutoConfigurationImportSelector类

List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
            AnnotationAttributes attributes) {
//SpringFactoriesLoader是用来加载自动配置的类的 List
<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }

关于SpringBoot自动配置的原理:

在使用一个公用的 starter 的时候,只需要将相应的依赖添加到Maven 的配置文件当中即可,免去了自己需要引用很多依赖类,并且 SpringBoot 会自动进行类的自动配置

 

SpringBoot在启动的时候就会到AutoConfigurationImportSelector这个类里面

SpringFactoiesLoader会扫描依赖的jar包中的META-INF/spring.factoies文件,该文件的格式都是key=value的格式。

key是一个接口的名字,value是实现类的名字,如果value有多个值,则用逗号分隔。

而我们上面提到的@EnableAutoConfiguration也是利用这个原理去扫描所有的自动配置类,以该注解的全限定类名作为key,所有的默认配置类为值。

SpringFactoiesLoader内部有一个静态的双层ConcurrentMap,用来存储这些key-value,第一层map的key是classloader,springboot默认的classloader是appClassLoader,value则是一个MultiValueMap,是spring自己实现的一个hashmap。而这个MultiValueMap的key就是spring.factoies文件中的key,value是一个list,即spring.factoies文件中的value。SpringFactoiesLoader利用缓存机制,只在第一次扫描所有的META-INF/spring.factoies文件时,就把所有的key-value都加载到这个map中,后面再进从中获取值时,直接从map中取就可以了,就不需要再重新扫描了。

 

@Conditional注解的条件,进行自动配置并将 Bean 注入 Spring Context 上下文当中。

@ImportAutoConfiguration({MyServiceAutoConfiguration.class}) 指定自动配置哪些类。指定配置自己的类。

 

springboot初始化过程中主要是扫描两个spring.factoies文件,其中定义的key-value中的类,是整个启动过程中要用到的。一个是spring-boot-2.0.3.RELEASE中的,一个是spring-boot-autoconfigure包中的。这两个jar包中的文件定义整个启动流程中要执行的所有默认配置好的类。

@ComponentScan

默认扫描当前包及其子包下面被@component,@Controller,@Service,@Repository标记标注的类然后纳入spring管理容器中去

 

@ResponseBody

表示该方法的返回结果直接写入HTTP response body中,一般在异步获取数据时使用,用于构建RESTful的api。在使用@RequestMapping后,返回值通常解析为跳转路径,加上@responsebody后返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。比如异步获取json数据,加上@Responsebody后,会直接返回json数据。该注解一般会配合@RequestMapping一起使用。示例代码:

@RestController

是@Controller和@ResponseBody的合集,表示这是个控制器bean,并且是将函数的返回值直 接填入HTTP响应体中,是REST风格的控制器。

 

@RequestMapping:

提供路由信息,负责URL到Controller中的具体函数的映射。

关于RequestMapping:

其中的一些属性:

value:请求的实际地址

method:get,post请求等

consumes:指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;

produces:指定返回类型

headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。 映射请求的标头,缩小主映射。

params:

@RequestMapping(value = "/pets", method = RequestMethod.GET, headers="Referer=http://www.ifeng.com/")
表示:仅处理request的header中包含了指定“Refer”请求头和对应值为“http://www.ifeng.com/”的请求;

@RequestMapping加到接口上也会生效:

启动时在向容器注入Controller的Bean(HandlerAdapter)时做了处理。controller类通过反射获取到接口的注解信息,并组装到Controller的Bean中。

https://blog.csdn.net/forezp/article/details/80069961

 

关于RequestMapping的整个过程:

在springBoot项目启东时候,扫描controller会把@RequestMapping的方法也加入到一个集合,放入到上下文环境中。

 

将类层次的RequestMapping和方法级别的RequestMapping结合  (createRequestMappingInfo) 

当请求到达时,去urlMap中需找匹配的url,以及获取对应mapping实例,然后去handlerMethods中获取匹配HandlerMethod实例。

发起请求后的执行流程是:检查request类型-->获取匹配的Handlemethod-->查找拦截器-->组成HandlerExecutionChain执行链-->获取方法执行链对象的适配器(HandlerAdapter)-->然后反射执行业务方法。

HandlerExecutionChain getHandler(HttpServletRequest request);

请求来的时候进入doDispatch方法,只简述一下里面的几个方法:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
         processedRequest = checkMultipart(request);
...
         mappedHandler = getHandler(processedRequest);//获取匹配的执行链
         ...
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//根据匹配到的执行链对象,获取合适的适配器
}

HandlerExecutionChain getHandler(HttpServletRequest request);

HandlerMapping 是由 DispatcherServlet 调用,DispatcherServlet 会从容器中取出所有 HandlerMapping 实例并遍历,让 HandlerMapping 实例根据自己实现类的方式去尝试查找 Handler,而 HandlerMapping 具体有哪些实现类下面就会详细分析。

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 这些 HandlerMapping 在容器初始化时创建,在 initHandlerMappings 时放入集合中
    for (HandlerMapping hm : this.handlerMappings) {
        HandlerExecutionChain handler = hm.getHandler(request);
        if (handler != null) {
            return handler;
        }
    }
    return null;
}

https://www.cnblogs.com/tengyunhao/p/7658952.html 还需要经常看

https://www.cnblogs.com/javammc/p/8600509.html

 

@Qualifier:

当有多个同一类型的Bean时,可以用@Qualifier(“name”)来指定。比如加service注解,在serviceImp需要加名字@service("userService")

与@Autowired配合使用,在接口有多个实现类的时候通过这个指定实现类。

 

@Autowired和@Resource(这两个功能是一样的)

都是注入Bean用的,Autowired默认按类型装配,如果需要按名称装配,需要配合Qualifier,这个是spring框架提供的

Resource默认按名称进行装配,通过name属性进行指定,这个是jdk提供的注解,如果@Resource不指定name就会退化成@Autowired

posted @ 2019-04-08 20:04  LeeJuly  阅读(1730)  评论(0)    收藏  举报