栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Springboot2

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

文章目录
  • springboot2
    • 一、入门
      • 1 、系统要求
      • 1.1 maven设置
      • 2 、HelloWorld
      • 2.1、 创建maven工程
      • 2.2 、引入依赖
      • 2.3、创建主程序
      • 2.4、编写业务
      • 2.5、测试
      • 2.6、简化配置
      • 2.7、简化部署
    • 二、自动配置原理
      • 1、SpringBoot特点
        • 1.1、依赖管理
        • 1.2、自动配置
      • 2、容器功能
        • 2.1、组件添加
        • 2.2、原生配置文件引入
        • 2.3、配置绑定
        • 3.1、引导加载自动配置类
        • 3.2、按需开启自动配置项
        • 3.3、修改默认配置
        • 总结:
        • 3.4、最佳实践
      • 4、开发小技巧
        • 4.1、Lombok
        • 4.2、dev-tools
        • 4.3、Spring Initailizr(项目初始化向导)
          • 1、自动依赖引入
          • 2、自动创建项目结构
          • 3、自动编写好主配置类
    • 三、核心功能
      • 1、配置文件
            • 配置提示
      • 2、Web开发
        • 1、SpringMVC自动配置概览
        • 2、简单功能分析
        • 3、请求参数处理
        • 4、数据响应与内容协商
          • 1、响应JSON
          • 2、内容协商
        • **5、视图解析与模板引擎**
        • 6、拦截器
        • 7、文件上传
        • 8、异常处理
        • 9、Web原生组件注入(Servlet、Filter、Listener)
        • 10、嵌入式Servlet容器
        • 11、定制化原理
      • 3、数据访问
      • 4、单元测试
        • 1、JUnit5 的变化
        • 2、JUnit5常用注解
        • 3、断言(assertions)
            • 1、简单断言
            • 2、数组断言
            • 3、组合断言
            • 4、异常断言
            • 5、超时断言
            • 6、快速失败
        • 4、前置条件(assumptions)
        • 5、嵌套测试
        • 6、参数化测试
        • 7、迁移指南
      • 5、指标监控
        • 1、SpringBoot Actuator
          • 1、简介
          • 2、1.x与2.x的不同
          • 3、如何使用
          • 4、可视化
        • 2、Actuator Endpoint
          • 1、最常使用的端点
          • 2、Health Endpoint
          • 3、Metrics Endpoint
          • 4、管理Endpoints
            • **1、开启与禁用Endpoints**
            • 2、暴露Endpoints
        • 3、定制 Endpoint
          • 1、定制 Health 信息
          • 2、定制info信息
            • 1、编写配置文件
            • 2、编写InfoContributor
            • 3、定制Metrics信息
            • 4、定制Endpoint
      • 6、原理解析
        • 1、Profile功能
          • 1、application-profile功能
          • 2、@Profile条件装配功能
          • 3、profile分组
        • 2、外部化配置
          • 1、外部配置源
          • 2、配置文件查找位
          • 3、配置文件加载顺序:
          • 4、指定环境优先,外部优先,后面的可以覆盖前面的同名配置项
        • 3、自定义starter
          • 1、starter启动原理
          • 2、自定义starter
        • 4、SpringBoot原理
          • 1、SpringBoot启动过程
          • 2、Application Events and Listeners
          • 3、ApplicationRunner 与 CommandLineRunner
          • 2、Application Events and Listeners
          • 3、ApplicationRunner 与 CommandLineRunner

springboot2 一、入门 1 、系统要求
  • Java 8 兼容java14 .
  • Maven 3.3+
  • idea 2019.1.2
1.1 maven设置

      
        nexus-aliyun
        central
        Nexus aliyun
        http://maven.aliyun.com/nexus/content/groups/public
      
  

  
         
              jdk-1.8
              
                true
                1.8
              
              
                1.8
                1.8
                1.8
              
         
  
2 、HelloWorld

需求:浏览发送/hello请求,响应 Hello,Spring Boot 2

2.1、 创建maven工程 2.2 、引入依赖

        org.springframework.boot
        spring-boot-starter-parent
        2.3.4.RELEASE
    


    
        
            org.springframework.boot
            spring-boot-starter-web
        

    
2.3、创建主程序

SpringApplication.run()会返回IOC容器

@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class,args);
    }
}
2.4、编写业务
@RestController
public class HelloController {


    @RequestMapping("/hello")
    public String handle01(){
        return "Hello, Spring Boot 2!";
    }


}
2.5、测试

直接运行main方法

2.6、简化配置

只要在resource中配置一个application.properties,所有的配置都可以在这配置

server.port=8888
2.7、简化部署

把项目打成jar包,直接在目标服务器执行即可。即使是web服务,也不再需要打成jar包,因为该插件中包含已编译类以及代码需要运行的所有 jar 依赖项的存档。

 
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

若无法运行成功,尝试关闭cmd窗口的快速编辑模式

二、自动配置原理 1、SpringBoot特点 1.1、依赖管理
  • 父项目做依赖管理
依赖管理    

        org.springframework.boot
        spring-boot-starter-parent
        2.3.4.RELEASE


他的父项目
 
    org.springframework.boot
    spring-boot-dependencies
    2.3.4.RELEASE
  


  • 开发导入starter场景启动器
1、见到很多 spring-boot-starter-* : *就某种场景
2、只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
3、SpringBoot所有支持的场景
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
4、见到的  *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
5、所有场景启动器最底层的依赖

  org.springframework.boot
  spring-boot-starter
  2.3.4.RELEASE
  compile

  • 无需关注版本号,自动版本仲裁
  1. 引入依赖默认都可以不写版本

  2. 引入非版本仲裁的jar,要写版本号。

  • 可以修改默认版本号
1、查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。
2、在当前项目里面重写配置
    
        5.1.43
    
1.2、自动配置
  • 自动配好Tomcat

    • 引入Tomcat依赖。
    • 配置Tomcat
  • 自动配好SpringMVC

    • 引入SpringMVC全套组件
    • 自动配好SpringMVC常用组件(功能)
  • 自动配好Web常见功能,如:字符编码问题

    • SpringBoot帮我们配置好了所有web开发的常见场景
  • 默认的包结构

    • 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
    • 无需以前的包扫描配置
    • 想要改变扫描路径,@SpringBootApplication(scanBasePackages=“com.atguigu”)
      • 或者@ComponentScan 指定扫描路径
@SpringBootApplication
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.atguigu.boot")
  • 各种配置拥有默认值

    • 默认配置最终都是映射到某个类上,如:MultipartProperties
    • 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
  • 按需加载所有自动配置项

    • 非常多的starter
    • 引入了哪些场景这个场景的自动配置才会开启
    • SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
2、容器功能 2.1、组件添加

1、@Configuration

基本使用

proxyBeanMethods = false/true

该功能能决定内部的bean是否要被代理来巩固bean生命周期表现。比如即使用户直接调取了bean方法,也能返回一个单例实例。

当值为True时,用户调用组件注册方法,会由内部代理来指向该类方法,并返回一个单例实例。被称作“Full Mode”,往往用在需要组件依赖时。该特质要求配置类满足CGLIB子类,并且类中的方法不能是final。

当值为False时,用户会直接调用该类。多次调用,会导致返回的对象引用不一致。这也被叫做“Lite Mode”,轻量级操作,节约了时间。

●Full模式与Lite模式
○示例
■配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
■配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式

#############################Configuration使用示例######################################################

@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {

    
    @Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
    public User user01(){
        User zhangsan = new User("zhangsan", 18);
        //user组件依赖了Pet组件
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }

    @Bean("tom")
    public Pet tomcatPet(){
        return new Pet("tomcat");
    }
}


################################@Configuration测试代码如下########################################
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.atguigu.boot")
public class MainApplication {

    public static void main(String[] args) {
        //1、返回我们IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

        //2、查看容器里面的组件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

        //3、从容器中获取组件

        Pet tom01 = run.getBean("tom", Pet.class);

        Pet tom02 = run.getBean("tom", Pet.class);

        System.out.println("组件:"+(tom01 == tom02));


        //4、com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892
        MyConfig bean = run.getBean(MyConfig.class);
        System.out.println(bean);

        //如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。
        //保持组件单实例
        User user = bean.user01();
        User user1 = bean.user01();
        System.out.println(user == user1);


        User user01 = run.getBean("user01", User.class);
        Pet tom = run.getBean("tom", Pet.class);

        System.out.println("用户的宠物:"+(user01.getPet() == tom));

    }
}

2、@Bean、@Component、@Controller、@Service、@Repository

用法与spring一样

3、@ComponentScan、@Import

 * @Import({User.class, DBHelper.class})
 *      给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
 *
 *
 *
 */

@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
}

4、@Conditional

条件装配:满足Conditional指定的条件,则进行组件注入

=====================测试条件装配==========================
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
//@ConditionalOnBean(name = "tom")
@ConditionalOnMissingBean(name = "tom")
public class MyConfig {


    

    @Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
    public User user01(){
        User zhangsan = new User("zhangsan", 18);
        //user组件依赖了Pet组件
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }

    @Bean("tom22")
    public Pet tomcatPet(){
        return new Pet("tomcat");
    }
}

public static void main(String[] args) {
        //1、返回我们IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

        //2、查看容器里面的组件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

        boolean tom = run.containsBean("tom");
        System.out.println("容器中Tom组件:"+tom);

        boolean user01 = run.containsBean("user01");
        System.out.println("容器中user01组件:"+user01);

        boolean tom22 = run.containsBean("tom22");
        System.out.println("容器中tom22组件:"+tom22);


    }
2.2、原生配置文件引入

1、@ImportResource

======================beans.xml=========================



    
        
        
    

    
        
    

@ImportResource("classpath:beans.xml")
public class MyConfig {}

======================测试=================
        boolean haha = run.containsBean("haha");
        boolean hehe = run.containsBean("hehe");
        System.out.println("haha:"+haha);//true
        System.out.println("hehe:"+hehe);//true
2.3、配置绑定

如何使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用;

@ConfigurationProperties

2、@Component + @ConfigurationProperties

@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {

    private String brand;
    private Integer price;

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + ''' +
                ", price=" + price +
                '}';
    }
}

3、@EnableConfigurationProperties + @ConfigurationProperties

如果不在对应类中写上@Component注入IOC容器,那就要在配置类中写上@EnableConfigurationProperties(xxx.class)

在对应类中写上@ConfigurationProperties

@EnableConfigurationProperties(Car.class)
//1、开启Car配置绑定功能
//2、把这个Car这个组件自动注册到容器中
public class MyConfig {
}
3.1、引导加载自动配置类
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{}


======================

1、@SpringBootConfiguration

@Configuration。代表当前是一个配置类

2、@ComponentScan

指定扫描哪些,Spring注解;

3、@EnableAutoConfiguration

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

1、@AutoConfigurationPackage

自动配置包 指定了默认的包规则

@Import(AutoConfigurationPackages.Registrar.class)  //给容器中导入一个组件
public @interface AutoConfigurationPackage {}

//利用Registrar给容器中导入一系列组件
//将指定的一个包下的所有组件导入进来?MainApplication 所在包下。

2、@Import(AutoConfigurationImportSelector.class)

1、利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
2、调用List configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
3、利用工厂加载 Map> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
4、从META-INF/spring.factories位置来加载一个文件。
    默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
    spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
spring-boot-autoconfigure-2.3.4.RELEASE.jar/META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration,
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcTransactionManagerAutoConfiguration,
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration,
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration,
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,
org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration
3.2、按需开启自动配置项
虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
按照条件装配规则(@Conditional),最终会按需配置。
3.3、修改默认配置
        @Bean
        @ConditionalOnBean(MultipartResolver.class)  //容器中有这个类型组件
        @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
        public MultipartResolver multipartResolver(MultipartResolver resolver) {
            //给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
            //SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
            // Detect if the user has created a MultipartResolver but named it incorrectly
            return resolver;
        }
给容器中加入了文件上传解析器;

SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先

@Bean
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
    }
总结:
  • SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration

  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定

  • 生效的配置类就会给容器中装配很多组件

  • 只要容器中有这些组件,相当于这些功能就有了

  • 定制化配置

    • 用户直接自己@Bean替换底层的组件
    • 用户去看这个组件是获取的配置文件什么值就去修改。

xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 ----> application.properties

3.4、最佳实践
  • 引入场景依赖

    • https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
  • 查看自动配置了哪些(选做)

    • 自己分析,引入场景对应的自动配置一般都生效了
    • 配置文件中debug=true开启自动配置报告。Negative(不生效)Positive(生效)
  • 是否需要修改

    • 参照文档修改配置项
      • https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties
      • 自己分析。xxxxProperties绑定了配置文件的哪些。
    • 自定义加入或者替换组件
      • @Bean、@Component。。。
    • 自定义器 XXXXXCustomizer;
4、开发小技巧 4.1、Lombok

简化JavaBean开发

        
            org.projectlombok
            lombok
        


idea中搜索安装lombok插件
===============================简化JavaBean开发===================================
@NoArgsConstructor
//@AllArgsConstructor
@Data
@ToString
@EqualsAndHashCode
public class User {

    private String name;
    private Integer age;

    private Pet pet;

    public User(String name,Integer age){
        this.name = name;
        this.age = age;
    }


}



================================简化日志开发===================================
@Slf4j
@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String handle01(@RequestParam("name") String name){

        log.info("请求进来了....");

        return "Hello, Spring Boot 2!"+"你好:"+name;
    }
}
4.2、dev-tools
        
            org.springframework.boot
            spring-boot-devtools
            true
        

项目或者页面修改以后:Ctrl+F9后,项目会重新编译,然后就生效了;

4.3、Spring Initailizr(项目初始化向导)

1、自动依赖引入 2、自动创建项目结构 3、自动编写好主配置类 三、核心功能 1、配置文件

1.1、文件类型

1.1.1、properties

同以前的properties用法

1.1.2、yaml

YAML 是 “YAML Ain’t Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。

非常适合用来做以数据为中心的配置文件

基本语法

  • key: value;kv之间有空格
  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • '#'表示注释
  • 字符串无需加引号,如果要加,’ '与" "表示字符串内容 会被 转义/不转义

数据类型

  • 字面量:单个的、不可再分的值。date、boolean、string、number、null
k: v
  • 对象:键值对的集合。map、hash、set、object
行内写法:  k: {k1:v1,k2:v2,k3:v3}
#或
k: 
  k1: v1
  k2: v2
  k3: v3
  • 数组:一组按次序排列的值。array、list、queue
行内写法:  k: [v1,v2,v3]
#或者
k:
 - v1
 - v2
 - v3

示例

@Data
public class Person {

    private String userName;
    private Boolean boss;
    private Date birth;
    private Integer age;
    private Pet pet;
    private String[] interests;
    private List animal;
    private Map score;
    private Set salarys;
    private Map> allPets;
}

@Data
public class Pet {
    private String name;
    private Double weight;
}
# yaml表示以上对象
person:
  userName: zhangsan
  boss: false
  birth: 2019/12/12 20:12:33
  age: 18
  pet: 
    name: tomcat
    weight: 23.4
  interests: [篮球,游泳]
  animal: 
    - jerry
    - mario
  score:
    english: 
      first: 30
      second: 40
      third: 50
    math: [131,140,148]
    chinese: {first: 128,second: 136}
  salarys: [3999,4999.98,5999.99]
  allPets:
    sick:
      - {name: tom}
      - {name: jerry,weight: 47}
    health: [{name: mario,weight: 47}]

在yaml中,双引号不会转义,单引号会转义,在单引号中,n以作为字符串,在双引号中,n作为换行

配置提示

自定义的类和配置文件绑定一般没有提示。

导入插件

        
            org.springframework.boot
            spring-boot-configuration-processor
            true
        


 
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    
                        
                            org.springframework.boot
                            spring-boot-configuration-processor
                        
                    
                
            
        
    
2、Web开发 1、SpringMVC自动配置概览

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.(大多场景我们都无需自定义配置)

The auto-configuration adds the following features on top of Spring’s defaults:

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

    • 内容协商视图解析器和BeanName视图解析器
  • Support for serving static resources, including support for WebJars (covered later in this document)).

    • 静态资源(包括webjars)
  • Automatic registration of Converter, GenericConverter, and Formatter beans.

    • 自动注册 Converter,GenericConverter,Formatter
  • Support for HttpMessageConverters (covered later in this document).

    • 支持 HttpMessageConverters (后来我们配合内容协商理解原理)
  • Automatic registration of MessageCodesResolver (covered later in this document).

    • 自动注册 MessageCodesResolver (国际化用)
  • Static index.html support.

    • 静态index.html 页支持
  • Custom Favicon support (covered later in this document).

    • 自定义 Favicon
  • Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).

    • 自动使用 ConfigurableWebBindingInitializer ,(DataBinder负责将请求数据绑定到JavaBean上)

If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.

不用@EnableWebMvc注解。使用 @Configuration + WebMvcConfigurer 自定义规则

If you want to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, and still keep the Spring Boot MVC customizations, you can declare a bean of type WebMvcRegistrations and use it to provide custom instances of those components.

声明 WebMvcRegistrations 改变默认底层组件

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc, or alternatively add your own @Configuration-annotated DelegatingWebMvcConfiguration as described in the Javadoc of @EnableWebMvc.

使用 @EnableWebMvc+@Configuration+DelegatingWebMvcConfiguration 全面接管SpringMVC

2、简单功能分析

2.1、静态资源访问

1、静态资源目录

只要静态资源放在类路径下:/static(or/publicor/resourcesor/META-INF/resources`

访问 : 当前项目根路径/ + 静态资源名

原理: 静态映射 private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;

3、欢迎页的处理规则

HandlerMapping:处理器映射。保存了每一个Handler能处理哪些请求。    

@Bean
    public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
            FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
        WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
                new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
                this.mvcProperties.getStaticPathPattern());
        welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
        welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
        return welcomePageHandlerMapping;
    }

WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,
        ApplicationContext applicationContext, Optional welcomePage, String staticPathPattern) {
    if (welcomePage.isPresent() && "
@Data
public class Person {
    
    private String userName;
    private Integer age;
    private Date birth;
    private Pet pet;
    
}

@Data
public class Pet {

    private String name;
    private String age;

}

2、POJO封装过程

  • ServletModelAttributeMethodProcessor

3、参数处理原理

  • HandlerMapping中找到能处理请求的Handler(Controller.method())
  • 为当前Handler 找一个适配器 HandlerAdapter; RequestMappingHandlerAdapter
  • 适配器执行目标方法并确定方法参数的每一个值

1、HandlerAdapter

0 - 支持方法上标注@RequestMapping

1 - 支持函数式编程的

xxxxxx

2、执行目标方法

// Actually invoke the handler.
//DispatcherServlet -- doDispatch
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
mav = invokeHandlerMethod(request, response, handlerMethod); //执行目标方法


//ServletInvocableHandlerMethod
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
//获取方法的参数值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);

3、参数解析器-HandlerMethodArgumentResolver

确定将要执行的目标方法的每一个参数的值是什么;

SpringMVC目标方法能写多少种参数类型。取决于参数解析器。

  • 当前解析器是否支持解析这种参数
  • 支持就调用 resolveArgument

4、返回值处理器

5、如何确定目标方法每一个参数的值

============InvocableHandlerMethod==========================
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {

        MethodParameter[] parameters = getMethodParameters();
        if (ObjectUtils.isEmpty(parameters)) {
            return EMPTY_ARGS;
        }

        Object[] args = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            MethodParameter parameter = parameters[i];
            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
            args[i] = findProvidedArgument(parameter, providedArgs);
            if (args[i] != null) {
                continue;
            }
            if (!this.resolvers.supportsParameter(parameter)) {
                throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
            }
            try {
                args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
            }
            catch (Exception ex) {
                // Leave stack trace for later, exception may actually be resolved and handled...
                if (logger.isDebugEnabled()) {
                    String exMsg = ex.getMessage();
                    if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                        logger.debug(formatArgumentError(parameter, exMsg));
                    }
                }
                throw ex;
            }
        }
        return args;
    }

5.1、挨个判断所有参数解析器那个支持解析这个参数

    @Nullable
    private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
        HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
        if (result == null) {
            for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
                if (resolver.supportsParameter(parameter)) {
                    result = resolver;
                    this.argumentResolverCache.put(parameter, result);
                    break;
                }
            }
        }
        return result;
    }

5.2、解析这个参数的值

调用各自 HandlerMethodArgumentResolver 的 resolveArgument 方法即可

5.3、自定义类型参数 封装POJO

ServletModelAttributeMethodProcessor 这个参数处理器支持

是否为简单类型。

public static boolean isSimpleValueType(Class type) {
		return (Void.class != type && void.class != type &&
				(ClassUtils.isPrimitiveOrWrapper(type) ||
				Enum.class.isAssignableFrom(type) ||
				CharSequence.class.isAssignableFrom(type) ||
				Number.class.isAssignableFrom(type) ||
				Date.class.isAssignableFrom(type) ||
				Temporal.class.isAssignableFrom(type) ||
				URI.class == type ||
				URL.class == type ||
				Locale.class == type ||
				Class.class == type));
	}
@Override
	@Nullable
	public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

		Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
		Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");

		String name = ModelFactory.getNameForParameter(parameter);
		ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
		if (ann != null) {
			mavContainer.setBinding(name, ann.binding());
		}

		Object attribute = null;
		BindingResult bindingResult = null;

		if (mavContainer.containsAttribute(name)) {
			attribute = mavContainer.getModel().get(name);
		}
		else {
			// Create attribute instance
			try {
				attribute = createAttribute(name, parameter, binderFactory, webRequest);
			}
			catch (BindException ex) {
				if (isBindExceptionRequired(parameter)) {
					// No BindingResult parameter -> fail with BindException
					throw ex;
				}
				// Otherwise, expose null/empty value and associated BindingResult
				if (parameter.getParameterType() == Optional.class) {
					attribute = Optional.empty();
				}
				bindingResult = ex.getBindingResult();
			}
		}

		if (bindingResult == null) {
			// Bean property binding and validation;
			// skipped in case of binding failure on construction.
			WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
			if (binder.getTarget() != null) {
				if (!mavContainer.isBindingDisabled(name)) {
					bindRequestParameters(binder, webRequest);
				}
				validateIfApplicable(binder, parameter);
				if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
					throw new BindException(binder.getBindingResult());
				}
			}
			// Value type adaptation, also covering java.util.Optional
			if (!parameter.getParameterType().isInstance(attribute)) {
				attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
			}
			bindingResult = binder.getBindingResult();
		}

		// Add resolved attribute and BindingResult at the end of the model
		Map bindingResultModel = bindingResult.getModel();
		mavContainer.removeAttributes(bindingResultModel);
		mavContainer.addAllAttributes(bindingResultModel);

		return attribute;
	}

WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);

WebDataBinder :web数据绑定器,将请求参数的值绑定到指定的JavaBean里面

WebDataBinder 利用它里面的 Converters 转换器将请求数据转成指定的数据类型。再次封装到JavaBean中

GenericConversionService:在设置每一个值的时候,找它里面的所有converter那个可以将这个数据类型(request带来参数的字符串)转换到指定的类型(JavaBean – Integer)

byte – > file

转换器总接口

@FunctionalInterfacepublic interface Converter

未来我们可以给WebDataBinder里面放自己的Converter;

自定义 Converter

@Configuration(proxyBeanMethods = false)
public class WebConfig {

    @Bean
    public WebMvcConfigurer webMvcConfigurer(){
        return new WebMvcConfigurer() {
            //矩阵变量
            @Override
            public void configurePathMatch(PathMatchConfigurer configurer) {
                UrlPathHelper urlPathHelper = new UrlPathHelper();
                urlPathHelper.setRemoveSemicolonContent(false);
                configurer.setUrlPathHelper(urlPathHelper);
            }

            //自定义转换器
            @Override
            public void addFormatters(FormatterRegistry registry) {
                registry.addConverter(new Converter() {

                    @Override
                    public Person convert(String source) {
                        if(!StringUtils.isEmpty(source)){
                            Person person = new Person();
                            String[] split = source.split(",");
                            person.setName(split[0]);
                            person.setAge(Integer.parseInt(split[1]));
                            return person;
                        }
                        return null;
                    }
                });
            }
        };
    }
}

6、目标方法执行完成

将所有的数据都放在 ModelAndViewContainer;包含要去的页面地址View。还包含Model数据。

7、处理派发结果

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

渲染:renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);

InternalResourceView:
@Override
	protected void renderMergedOutputModel(
			Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		// Expose the model object as request attributes.
		exposeModelAsRequestAttributes(model, request);

		// Expose helpers as request attributes, if any.
		exposeHelpers(request);

		// Determine the path for the request dispatcher.
		String dispatcherPath = prepareForRendering(request, response);

		// Obtain a RequestDispatcher for the target resource (typically a JSP).
		RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
		if (rd == null) {
			throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
					"]: Check that the corresponding file exists within your web application archive!");
		}

		// If already included or response already committed, perform include, else forward.
		if (useInclude(request, response)) {
			response.setContentType(getContentType());
			if (logger.isDebugEnabled()) {
				logger.debug("Including [" + getUrl() + "]");
			}
			rd.include(request, response);
		}

		else {
			// Note: The forwarded resource is supposed to determine the content type itself.
			if (logger.isDebugEnabled()) {
				logger.debug("Forwarding to [" + getUrl() + "]");
			}
			rd.forward(request, response);
		}
	}
暴露模型作为请求域属性
// Expose the model object as request attributes.
		exposeModelAsRequestAttributes(model, request);
protected void exposeModelAsRequestAttributes(Map model,
			HttpServletRequest request) throws Exception {

    //model中的所有数据遍历挨个放在请求域中
		model.forEach((name, value) -> {
			if (value != null) {
				request.setAttribute(name, value);
			}
			else {
				request.removeAttribute(name);
			}
		});
	}
4、数据响应与内容协商

1、响应JSON

1.1、jackson.jar+@ResponseBody

        
            org.springframework.boot
            spring-boot-starter-web
        
web场景自动引入了json场景
    
      org.springframework.boot
      spring-boot-starter-json
      2.3.4.RELEASE
      compile
    

给前端自动返回json数据;

1、返回值解析器

try {
			this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
	@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

		HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
		if (handler == null) {
			throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
		}
		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}
RequestResponseBodyMethodProcessor  	
@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

		mavContainer.setRequestHandled(true);
		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

		// Try even with null return value. ResponseBodyAdvice could get involved.
        // 使用消息转换器进行写出操作
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}

2、返回值解析器原理

1、返回值处理器判断是否支持这种类型返回值 supportsReturnType

2、返回值处理器调用 handleReturnValue 进行处理

3、RequestResponseBodyMethodProcessor 可以处理返回值标了@ResponseBody 注解的。

利用 MessageConverters 进行处理 将数据写为json

1、内容协商(浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型)

2、服务器最终根据自己自身的能力,决定服务器能生产出什么样内容类型的数据,

3、SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter ,看谁能处理?

①得到MappingJackson2HttpMessageConverter可以将对象写为json

②利用MappingJackson2HttpMessageConverter将对象转为json再写出去。

SpringMVC支持返回值

ModelAndView
Model
View
ResponseEntity 
ResponseBodyEmitter
StreamingResponseBody
HttpEntity
HttpHeaders
Callable
DeferredResult
ListenableFuture
CompletionStage
WebAsyncTask
有 @ModelAttribute 且为对象类型的
@ResponseBody 注解 ---> RequestResponseBodyMethodProcessor;

1.3、HTTPMessageConverter原理

1、MessageConverter规范

HttpMessageConverter: 看是否支持将 此 Class类型的对象,转为MediaType类型的数据。

例子:Person对象转为JSON。或者 JSON转为Person

2、默认的MessageConverter

  • 0 - 只支持Byte类型的
  • 1 - String
  • 2 - String
  • 3 - Resource
  • 4 - ResourceRegion
  • 5 - DOMSource.class SAXSource.class**) StAXSource.class StreamSource.class Source.class
  • 6 - MultiValueMap
  • 7 - true
  • 8 - true
  • 9 - 支持注解方式xml处理的。

最终 MappingJackson2HttpMessageConverter 把对象转为JSON(利用底层的jackson的objectMapper转换的)

2、内容协商

根据客户端接收能力不同,返回不同媒体类型的数据。

只需要改变请求头中Accept字段。Http协议中规定的,告诉服务器本客户端可以接收的数据类型。

​ 1、引入xml依赖

 
            com.fasterxml.jackson.dataformat
            jackson-dataformat-xml

​ 2、开启浏览器参数方式内容协商功能

spring:
	mvc:
    contentnegotiation:
      favor-parameter: true  #开启请求参数内容协商模式

发请求:

http://localhost:8080/test/person?format=json

http://localhost:8080/test/person?format=xml

3、内容协商原理

  • 1、判断当前响应头中是否已经有确定的媒体类型。MediaType

  • 2、获取客户端支持接收的内容类型。(获取客户端Accept请求头字段)【application/xml】

    • contentNegotiationManager 内容协商管理器 默认使用基于请求头的策略
    • HeaderContentNegotiationStrategy 确定客户端可以接收的内容类型
  • 3、遍历循环所有当前系统的 MessageConverter,看谁支持操作这个对象(Person)

  • 4、找到支持操作Person的converter,把converter支持的媒体类型统计出来。

  • 5、客户端需要【application/xml】。服务端能力【10种、json、xml】

  • 6、进行内容协商的最佳匹配媒体类型
  • 7、用 支持 将对象转为 最佳匹配媒体类型 的converter。调用它进行转化 。

导入了jackson处理xml的包,xml的converter就会自动进来

WebMvcConfigurationSupport
jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);

if (jackson2XmlPresent) {
			Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
			if (this.applicationContext != null) {
				builder.applicationContext(this.applicationContext);
			}
			messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
		}

​ 5、自定义 MessageConverter

实现多协议数据兼容。json、xml、x-guigu

0、@ResponseBody 响应数据出去 调用 RequestResponseBodyMethodProcessor 处理

1、Processor 处理方法返回值。通过 MessageConverter 处理

2、所有 MessageConverter 合起来可以支持各种媒体类型数据的操作(读、写)

3、内容协商找到最终的 messageConverter;

public class PersonMessageConverter implements HttpMessageConverter {
    @Override
    public boolean canRead(Class clazz, MediaType mediaType) {
        return false;
    }

    @Override
    public boolean canWrite(Class clazz, MediaType mediaType) {
        return clazz.isAssignableFrom(Person.class);
    }

    @Override
    public List getSupportedMediaTypes() {
        return MediaType.parseMediaTypes("application/x-person");
    }

    @Override
    public Person read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }

    @Override
    public void write(Person person, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        String data = person.getName() + ";" + person.getAge();
        OutputStream body = outputMessage.getBody();
        body.write(data.getBytes(StandardCharsets.UTF_8));
    }
}

SpringMVC的什么功能,就一个入口给容器中添加一个 WebMvcConfigurer。

@Override
            public void extendMessageConverters(List> converters) {
                converters.add(new PersonMessageConverter());
            }

要让内容协商 通过format传参的方式支持我们的自定义格式,可以通过配置内容协商管理器:

@Configuration(proxyBeanMethods = false)
public class WebConfig {

    @Bean
    public WebMvcConfigurer webMvcConfigurer(){
        return new WebMvcConfigurer() {

            @Override
            public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
                Map mediaTypes = new HashMap<>();
                mediaTypes.put("json",MediaType.APPLICATION_JSON);
                mediaTypes.put("xml",MediaType.APPLICATION_XML);
                mediaTypes.put("person",MediaType.parseMediaType("application/x-person"));
                ParameterContentNegotiationStrategy parameterStrategy = new ParameterContentNegotiationStrategy(mediaTypes);
                configurer.strategies(Arrays.asList(parameterStrategy));
            }

            @Override
            public void configurePathMatch(PathMatchConfigurer configurer) {
                UrlPathHelper urlPathHelper = new UrlPathHelper();
                urlPathHelper.setRemoveSemicolonContent(false);
                configurer.setUrlPathHelper(urlPathHelper);
            }

            @Override
            public void addFormatters(FormatterRegistry registry) {
                registry.addConverter(new Converter() {

                    @Override
                    public Person convert(String source) {
                        if(!StringUtils.isEmpty(source)){
                            Person person = new Person();
                            String[] split = source.split(",");
                            person.setName(split[0]);
                            person.setAge(Integer.parseInt(split[1]));
                            return person;
                        }
                        return null;
                    }
                });
            }

            @Override
            public void extendMessageConverters(List> converters) {
                converters.add(new PersonMessageConverter());
            }
        };


    }
}

有可能我们添加的自定义的功能会覆盖默认很多功能,导致一些默认的功能失效。

大家考虑,上述功能除了我们完全自定义外?SpringBoot有没有为我们提供基于配置文件的快速修改媒体类型功能?怎么配置呢?【提示:参照SpringBoot官方文档web开发内容协商章节】

配置如下:

spring:
  mvc:
    contentnegotiation:
      favor-parameter: true
      media-types: { person: application/x-person }
5、视图解析与模板引擎

视图解析:SpringBoot默认不支持 JSP,需要引入第三方模板引擎技术实现页面渲染。

​ 1、视图解析

​ 1、视图解析原理流程

1、目标方法处理的过程中,所有数据都会被放在 ModelAndViewContainer 里面。包括数据和视图地址

2、方法的参数是一个自定义类型对象(从请求参数中确定的),把他重新放在 ModelAndViewContainer

3、任何目标方法执行完成以后都会返回 ModelAndView(数据和视图地址)。

4、processDispatchResult 处理派发结果(页面改如何响应)

  • 1、render(mv, request, response); 进行页面渲染逻辑

    • 1、根据方法的String返回值得到 View 对象【定义了页面的渲染逻辑】
      • 1、所有的视图解析器尝试是否能根据当前返回值得到View对象
      • 2、得到了 redirect:/main.html --> Thymeleaf new RedirectView()
      • 3、ContentNegotiationViewResolver 里面包含了下面所有的视图解析器,内部还是利用下面所有视图解析器得到视图对象。


      • 4、view.render(mv.getModelInternal(), request, response); 视图对象调用自定义的render进行页面渲染工作
        • RedirectView 如何渲染【重定向到一个页面】
        • 1、获取目标url地址
        • 2、response.sendRedirect(encodedURL);

视图解析:

    • 返回值以 forward: 开始: new InternalResourceView(forwardUrl); --> 转发request.getRequestDispatcher(path).forward(request, response);
    • 返回值以 redirect: 开始: new RedirectView() --》 render就是重定向
    • 返回值是普通字符串: new ThymeleafView()—>

我们还可以自定义视图解析器+自定义视图;

2、模板引擎-Thymeleaf

​ 1、thymeleaf简介

Thymeleaf is a modern server-side Java template engine for both web and standalone environments, capable of processing HTML, XML, JavaScript, CSS and even plain text.

Thymeleaf 是一个现代服务器端 Java 模板引擎,适用于 Web 和独立环境,能够处理 HTML、XML、JavaScript、CSS 甚至纯文本。

​ 2、基本语法

​ 1、表达式

表达式名字语法用途
变量取值${…}获取请求域、session域、对象等值
选择变量*{…}获取上下文对象值
消息#{…}获取国际化等值
链接@{…}生成链接
片段表达式~{…}jsp:include 作用,引入公共页面片段

​ 2、字面量

  • 文本值: ‘one text’ , ‘Another one!’ **,…**数字: 0 , 34 , 3.0 , 12.3 **,…**布尔值: true , false
  • 空值: null
  • 变量: one,two,… 变量不能有空格

​ 3、文本操作

  • 字符串拼接: +
  • 变量替换: |The name is ${name}|

​ 4、数学运算

  • 运算符: + , - , * , / , %

​ 5、布尔运算

  • 运算符: and , or
  • 一元运算: ! , not

​ 6、比较运算

  • 比较: > , < , >= , <= ( gt , lt , ge , le **)**等式: == , != ( eq , ne )

​ 7、条件运算

  • If-then: (if) ? (then)
  • If-then-else: (if) ? (then) : (else)
  • Default: (value) ?: (defaultvalue)

​ 8、特殊操作

  • 无操作: _

​ 3、设置属性值-th:attr

  • 设置单个值
  • 设置多个值

Springboot2

以上两个的代替写法 th:xxxx


所有h5兼容的标签写法

https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#setting-value-to-specific-attributes

​ 4、迭代


        Onions
        2.41
        yes


  Onions
  2.41
  yes

​ 5、条件运算

view

User is an administrator

User is a manager

User is some other thing

​ 6、属性优先级

OrderFeatureAttributes
1Fragment inclusionth:insert th:replace
2Fragment iterationth:each
3Conditional evaluationth:if th:unless th:switch th:case
4Local variable definitionth:object th:with
5General attribute modificationth:attr th:attrprepend th:attrappend
6Specific attribute modificationth:value th:href th:src ...
7Text (tag body modification)th:text th:utext
8Fragment specificationth:fragment
9Fragment removalth:remove

​ 3、thymeleaf使用

​ 1、引入Starter

        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        

​ 2、自动配置好了thymeleaf

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ThymeleafProperties.class)
@ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class })
@AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class })
public class ThymeleafAutoConfiguration { }

自动配好的策略

  • 1、所有thymeleaf的配置值都在 ThymeleafProperties

  • 2、配置好了 SpringTemplateEngine

  • 3、配好了 ThymeleafViewResolver

  • 4、我们只需要直接开发页面

    public static final String DEFAULT_PREFIX = “classpath:/templates/”;

    public static final String DEFAULT_SUFFIX = “.html”; //xxx.html

​ 3、页面开发




    
    Title


哈哈

去百度
去百度2

6、拦截器

1、HandlerInterceptor 接口

@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String requestURI = request.getRequestURI();
        log.info("preHandle拦截的请求路径是{}",requestURI);

        //登录检查逻辑
        HttpSession session = request.getSession();

        Object loginUser = session.getAttribute("loginUser");

        if(loginUser != null){
            //放行
            return true;
        }

        //拦截住。未登录。跳转到登录页
        request.setAttribute("msg","请先登录");
//        re.sendRedirect("/");
        request.getRequestDispatcher("/").forward(request,response);
        return false;
    }

    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle执行{}",modelAndView);
    }

    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion执行异常{}",ex);
    }
}

2、配置拦截器

@Configuration
public class AdminWebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("
    }
}
    • response.sendError 。error请求就会转给controller
    • 你的异常没有任何人能处理。tomcat底层 response.sendError。error请求就会转给controller
    • basicErrorController 要去的页面地址是 ErrorViewResolver ;
  • 自己调用response.error,请求也会被转发给basicErrorController进行处理。如果自己没有调用,并且异常没有任何人能够处理,tomact底层会自动调用response.sendError将请求转发给basicErrorController处理。

3、异常处理自动配置原理

  • ErrorMvcAutoConfiguration 自动配置异常处理规则

  • 容器中的组件:类型:DefaultErrorAttributes -> id:errorAttributes

  • public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver

    • DefaultErrorAttributes:定义错误页面中可以包含哪些数据。

    • 容器中的组件:类型:**BasicErrorController --> id:basicErrorController(json+白页 适配响应)

    • 处理默认 /error 路径的请求;页面响应 new ModelAndView(“error”, model);

    • 容器中有组件 View->id是error;(响应默认错误页)

    • 容器中放组件 BeanNameViewResolver(视图解析器);按照返回的视图名作为组件的id去容器中找View对象。

    • 容器中的组件:**类型:**DefaultErrorViewResolver -> id:conventionErrorViewResolver

    • 如果发生错误,会以HTTP的状态码 作为视图页地址(viewName),找到真正的页面

    • error/404、5xx.html

如果想要返回页面;就会找error视图【StaticView】。(默认是一个白页)

白页的内容就是由ErrorMvcAutoConfiguration这个类中的render方法渲染出来的

public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
            if (response.isCommitted()) {
                String message = this.getMessage(model);
                logger.error(message);
            } else {
                response.setContentType(TEXT_HTML_UTF8.toString());
                StringBuilder builder = new StringBuilder();
                Object timestamp = model.get("timestamp");
                Object message = model.get("message");
                Object trace = model.get("trace");
                if (response.getContentType() == null) {
                    response.setContentType(this.getContentType());
                }

                builder.append("Whitelabel Error Page").append("

This application has no explicit mapping for /error, so you are seeing this as a fallback.

").append("").append(timestamp).append("").append("There was an unexpected error (type=").append(this.htmlEscape(model.get("error"))).append(", status=").append(this.htmlEscape(model.get("status"))).append(")."); if (message != null) { builder.append("").append(this.htmlEscape(message)).append(""); } if (trace != null) { builder.append("").append(this.htmlEscape(trace)).append(""); } builder.append(""); response.getWriter().append(builder.toString()); } }

在BasicErrorController中:

1.返回json:

    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
    public ResponseEntity mediaTypeNotAcceptable(HttpServletRequest request) {
        HttpStatus status = this.getStatus(request);
        return ResponseEntity.status(status).build();
    }

2.返回错误页:

@RequestMapping(
    produces = {"text/html"}
)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
    HttpStatus status = this.getStatus(request);
    Map model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
    response.setStatus(status.value());
    ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
    return modelAndView != null ? modelAndView : new ModelAndView("error", model);
}

4、异常处理步骤流程

1、执行目标方法,目标方法运行期间有任何异常都会被catch、而且标志当前请求结束;并且用 dispatchException

2、进入视图解析流程(页面渲染)

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException),此时mv是null;

3、mv = processHandlerException;处理handler发生的异常,处理完成返回ModelAndView;

  • 1、遍历所有的 **handlerExceptionResolvers,看谁能处理当前异常【**HandlerExceptionResolver处理器异常解析器】

  • 2、系统默认的 异常解析器;

      • 1、如果没有任何人能处理最终底层就会发送 /error 请求。会被底层的BasicErrorController处理
      • 2、解析错误视图;遍历所有的 ErrorViewResolver 看谁能解析。

      • 3、默认的 DefaultErrorViewResolver ,作用是把响应状态码作为错误页的地址,error/500.html
      • 4、模板引擎最终响应这个页面 error/500.html
9、Web原生组件注入(Servlet、Filter、Listener)

1、使用Servlet API

在启动类中使用@ServletComponentScan(basePackages = “com.ekertree.admin”) :指定原生Servlet组件都放在那里

在servlet类中使用@WebServlet(urlPatterns = “/my”):效果:直接响应。

@WebFilter(urlPatterns={“/css @Override protected void doHealthCheck(Health.Builder builder) throws Exception { Map mes = new HashMap<>(); // 进行判断逻辑 if (1==1){ //直接反馈 health 状态为 UP // builder.up(); //第二种方式 builder.status(Status.UP); mes.put("code","666"); mes.put("mess","逻辑通过"); }else { //设置 health 状态为 DOWN // builder.down(); //第二种方式 builder.status(Status.OUT_OF_SERVICE); mes.put("code","000"); mes.put("mess","逻辑不通过"); } //结果 builder.withDetail("num",789) .withDetail("详细信息",mes); } }

management:
    health:
      enabled: true
      show-details: always #总是显示详细信息。可显示每个模块的状态信息
2、定制info信息
management:
  info:
    env:
      enabled: true

两种方式

1、编写配置文件
info:
  appName: boot-admin
  version: 2.0.1
  mavenProjectName: @project.artifactId@  #使用@@可以获取maven的pom文件值
  mavenProjectVersion: @project.version@
2、编写InfoContributor
@Component
public class AppInfoContributor implements InfoContributor {
    @Override
    public void contribute(Info.Builder builder) {
        builder.withDetail("msg", "wori")
                .withDetail("err", "aaaaaaa");
    }
}

http://localhost:8080/actuator/info 会输出以上方式返回的所有info信息

3、定制Metrics信息

1、SpringBoot支持自动适配的Metrics

●JVM metrics, report utilization of:
○Various memory and buffer pools
○Statistics related to garbage collection
○Threads utilization
○Number of classes loaded/unloaded
●CPU metrics
●File descriptor metrics
●Kafka consumer and producer metrics
●Log4j2 metrics: record the number of events logged to Log4j2 at each level
●Logback metrics: record the number of events logged to Logback at each level
●Uptime metrics: report a gauge for uptime and a fixed gauge representing the application’s absolute start time
●Tomcat metrics (server.tomcat.mbeanregistry.enabled must be set to true for all Tomcat metrics to be registered)
●Spring Integration metrics

2、增加定制Metrics

class MyService{
    Counter counter;
    public MyService(MeterRegistry meterRegistry){
         counter = meterRegistry.counter("myservice.method.running.counter");
    }

    public void hello() {
        counter.increment();
    }
}


//也可以使用下面的方式
@Bean
MeterBinder queueSize(Queue queue) {
    return (registry) -> Gauge.builder("queueSize", queue::size).register(registry);
}
4、定制Endpoint
@Endpoint(id = "test")
@Component
public class TestEndPoint {

    @ReadOperation
    public Map getTestInfo(){
        return Collections.singletonMap("testInfo", "test engine starting...");
    }

    @WriteOperation
    public void stopTest(){
        System.out.println("stop test engine....");
    }
}

场景:开发ReadinessEndpoint来管理程序是否就绪,或者LivenessEndpoint来管理程序是否存活;
当然,这个也可以直接使用 https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-kubernetes-probes

6、原理解析 1、Profile功能

为了方便多环境适配,springboot简化了profile功能。

1、application-profile功能

●默认配置文件 application.yaml;任何时候都会加载
●指定环境配置文件 application-{env}.yaml
●激活指定环境
○配置文件激活
○命令行激活:java -jar xxx.jar --spring.profiles.active=prod
■修改配置文件的任意值,命令行优先
●默认配置与环境配置同时生效
●同名配置项,profile配置优先

2、@Profile条件装配功能
@Configuration(proxyBeanMethods = false)
@Profile("production")
public class ProductionConfiguration {

    // ...

}
3、profile分组
spring.profiles.group.production[0]=proddb
spring.profiles.group.production[1]=prodmq

使用:--spring.profiles.active=production  激活
2、外部化配置

https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config

  1. Default properties (specified by setting SpringApplication.setDefaultProperties).
  2. @PropertySource annotations on your @Configuration classes. Please note that such property sources are not added to the Environment until the application context is being refreshed. This is too late to configure certain properties such as logging.* and spring.main.* which are read before refresh begins.
  3. Config data (such as application.properties files).
  4. A RandomValuePropertySource that has properties only in random.*.
  5. OS environment variables.
  6. Java System properties (System.getProperties()).
  7. JNDI attributes from java:comp/env.
  8. ServletContext init parameters.
  9. ServletConfig init parameters.
  10. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).
  11. Command line arguments.
  12. properties attribute on your tests. Available on @SpringBootTest and the test annotations for testing a particular slice of your application.
  13. @TestPropertySource annotations on your tests.
  14. Devtools global settings properties in the $HOME/.config/spring-boot directory when devtools is active.
1、外部配置源

常用:Java属性文件、YAML文件、环境变量、命令行参数;

2、配置文件查找位
  1. classpath 根路径 resource下或者java下都算根路径
  2. classpath 根路径下config目录
  3. jar包当前目录
  4. jar包当前目录的config目录
  5. /config子目录的直接子目录 (Linux系统中)
3、配置文件加载顺序:
  1. 当前jar包内部的application.properties和application.yml
  2. 当前jar包内部的application-{profile}.properties 和 application-{profile}.yml
  3. 引用的外部jar包的application.properties和application.yml
  4. 引用的外部jar包的application-{profile}.properties 和 application-{profile}.yml
4、指定环境优先,外部优先,后面的可以覆盖前面的同名配置项 3、自定义starter 1、starter启动原理

●autoconfigure包中配置使用 META-INF/spring.factories 中 EnableAutoConfiguration 的值,使得项目启动加载指定的自动配置类
●编写自动配置类 xxxAutoConfiguration -> xxxxProperties
○@Configuration
○@Conditional
○@EnableConfigurationProperties
○@Bean

引入starter — xxxAutoConfiguration — 容器中放入组件 ---- 绑定xxxProperties ---- 配置项

2、自定义starter

reey-hello-spring-boot-starter-autoconfigure(自动配置包)

功能类:

public class HelloService {

    @Autowired
    HelloProperties helloProperties;

    public String sayHello(String userName){
        return helloProperties.getPrefix() + ":" + userName + helloProperties.getSuffix();
    }
}

配置类:

@ConfigurationProperties("reey.hello")//绑定spring配置文件reey.hello下的配置
public class HelloProperties {

    private String prefix;
    private String suffix;

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public String getSuffix() {
        return suffix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
}

自动配置类:

@Configuration
@EnableConfigurationProperties(HelloProperties.class)//绑定配置类
public class HelloServiceAutoConfiguration {

    @ConditionalOnMissingBean(HelloService.class)//没有helloservice才注入
    @Bean
    public HelloService helloService(){
        HelloService helloService = new HelloService();
        return helloService;
    }
}

在recourses下创建META-INF文件夹,在文件夹下面创建spring.factories

填入自动配置:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.reey.hack.hello.auto.HelloServiceAutoConfiguration

做好自动配置包后安装到本地maven仓库

reey-hello-spring-boot-starter(启动器)

在启动器项目中引入自动配置包



    4.0.0

    com.reey
    reey-hack-spring-boot-starter
    1.0-SNAPSHOT

    
        
            com.reey
            reey-hack-spring-boot-starter-autoconfigure
            0.0.1-SNAPSHOT
        
    

将启动器包安装到本地仓库,即可被其他项目引用。

4、SpringBoot原理

Spring原理、SpringMVC原理、自动配置原理、SpringBoot原理

1、SpringBoot启动过程

创建 SpringApplication
○保存一些信息。
○判定当前应用的类型。ClassUtils。Servlet
○bootstrappers:初始启动引导器(List):去spring.factories文件中找 org.springframework.boot.Bootstrapper

public interface Bootstrapper {

	
	void intitialize(BootstrapRegistry registry);

}

○找 ApplicationContextInitializer;去spring.factories找 ApplicationContextInitializer
■List> initializers ○找 ApplicationListener ;应用监听器。去spring.factories找 **ApplicationListener** ■List

运行 SpringApplication
○StopWatch
○记录应用的启动时间
○创建引导上下文(Context环境)createBootstrapContext()
■获取到所有之前的 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置
○让当前应用进入headless模式。java.awt.headless
○获取所有 RunListener(运行监听器)【为了方便所有Listener进行事件感知】

​ ■getSpringFactoriesInstances 去spring.factories找 SpringApplicationRunListener.
​ ○遍历 SpringApplicationRunListener 调用 starting 方法;
​ ■相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting。
​ ○保存命令行参数;ApplicationArguments
​ ○准备环境 prepareEnvironment();
​ ■返回或者创建基础环境信息对象。StandardServletEnvironment
​ ■配置环境信息对象。
​ ●读取所有的配置源的配置属性值。
​ ■绑定环境信息
​ ■监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成
​ ○创建IOC容器(createApplicationContext())
​ ■根据项目类型(Servlet)创建容器,
​ ■当前会创建 AnnotationConfigServletWebServerApplicationContext
​ ○准备ApplicationContext IOC容器的基本信息 prepareContext()
​ ■保存环境信息
​ ■IOC容器的后置处理流程。
​ ■应用初始化器;applyInitializers;
​ ●遍历所有的 ApplicationContextInitializer 。调用 initialize.。来对ioc容器进行初始化扩展功能
​ ●遍历所有的 listener 调用 contextPrepared。EventPublishRunListenr;通知所有的监听器contextPrepared
​ ■所有的监听器 调用 contextLoaded。通知所有的监听器 contextLoaded;
​ ○刷新IOC容器。refreshContext
​ ■创建容器中的所有组件
​ ○容器刷新完成后工作?afterRefresh
​ ○所有监听 器 调用 listeners.started(context); 通知所有的监听器 started
​ ○调用所有runners;callRunners()
​ ■获取容器中的 ApplicationRunner

@FunctionalInterface
public interface ApplicationRunner {

	
	void run(ApplicationArguments args) throws Exception;

}

​ ■获取容器中的 CommandLineRunner

@FunctionalInterface
public interface CommandLineRunner {

	
	void run(String... args) throws Exception;

}

​ ■合并所有runner并且按照@Order进行排序
​ ■遍历所有的runner。调用 run 方法
​ ○如果以上有异常,
​ ■调用Listener 的 failed
​ ○调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 running
​ ○running如果有问题。继续通知 failed 。调用所有 Listener 的 failed;通知所有的监听器 failed

public class MyapplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("MyapplicationContextInitializer......initializing......");
    }
}

public class MyApplicationLisener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("MyApplicationLisener......");
    }
}

@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("MyApplicationRunner......run......");
    }
}

//应用启动时做一个一次性事情
@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("MyCommandLineRunner......run......");
    }
}

public class MySpringApplicationRunListener implements SpringApplicationRunListener {

    public MySpringApplicationRunListener(SpringApplication springApplication,String[] args) {

    }

    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("MySpringApplicationRunListener.....starting......");
    }

    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        System.out.println("MySpringApplicationRunListener.....environmentPrepared......");
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener.....contextPrepared......");
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener.....contextLoaded......");
    }

    @Override
    public void started(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("MySpringApplicationRunListener.....started......");
    }


    @Override
    public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("MySpringApplicationRunListener.....ready......");
    }


    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("MySpringApplicationRunListener.....failed......");
    }
}

spring.factories:

org.springframework.context.ApplicationContextInitializer=
  com.reey.hellotest.initializer.MyapplicationContextInitializer

org.springframework.context.ApplicationListener=
  com.reey.hellotest.initializer.MyApplicationLisener

org.springframework.boot.SpringApplicationRunListener=
  com.reey.hellotest.initializer.MySpringApplicationRunListener
2、Application Events and Listeners

https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-application-events-and-listeners

  • ApplicationContextInitializer
  • ApplicationListener
  • SpringApplicationRunListener
3、ApplicationRunner 与 CommandLineRunner

应用初始化器;applyInitializers;
​ ●遍历所有的 ApplicationContextInitializer 。调用 initialize.。来对ioc容器进行初始化扩展功能
​ ●遍历所有的 listener 调用 contextPrepared。EventPublishRunListenr;通知所有的监听器contextPrepared
​ ■所有的监听器 调用 contextLoaded。通知所有的监听器 contextLoaded;
​ ○刷新IOC容器。refreshContext
​ ■创建容器中的所有组件
​ ○容器刷新完成后工作?afterRefresh
​ ○所有监听 器 调用 listeners.started(context); 通知所有的监听器 started
​ ○调用所有runners;callRunners()
​ ■获取容器中的 ApplicationRunner

@FunctionalInterface
public interface ApplicationRunner {

	
	void run(ApplicationArguments args) throws Exception;

}

​ ■获取容器中的 CommandLineRunner

@FunctionalInterface
public interface CommandLineRunner {

	
	void run(String... args) throws Exception;

}

​ ■合并所有runner并且按照@Order进行排序
​ ■遍历所有的runner。调用 run 方法
​ ○如果以上有异常,
​ ■调用Listener 的 failed
​ ○调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 running
​ ○running如果有问题。继续通知 failed 。调用所有 Listener 的 failed;通知所有的监听器 failed

public class MyapplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("MyapplicationContextInitializer......initializing......");
    }
}

public class MyApplicationLisener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("MyApplicationLisener......");
    }
}

@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("MyApplicationRunner......run......");
    }
}

//应用启动时做一个一次性事情
@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("MyCommandLineRunner......run......");
    }
}

public class MySpringApplicationRunListener implements SpringApplicationRunListener {

    public MySpringApplicationRunListener(SpringApplication springApplication,String[] args) {

    }

    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("MySpringApplicationRunListener.....starting......");
    }

    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        System.out.println("MySpringApplicationRunListener.....environmentPrepared......");
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener.....contextPrepared......");
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener.....contextLoaded......");
    }

    @Override
    public void started(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("MySpringApplicationRunListener.....started......");
    }


    @Override
    public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("MySpringApplicationRunListener.....ready......");
    }


    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("MySpringApplicationRunListener.....failed......");
    }
}

spring.factories:

org.springframework.context.ApplicationContextInitializer=
  com.reey.hellotest.initializer.MyapplicationContextInitializer

org.springframework.context.ApplicationListener=
  com.reey.hellotest.initializer.MyApplicationLisener

org.springframework.boot.SpringApplicationRunListener=
  com.reey.hellotest.initializer.MySpringApplicationRunListener
2、Application Events and Listeners

https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-application-events-and-listeners

  • ApplicationContextInitializer
  • ApplicationListener
  • SpringApplicationRunListener
3、ApplicationRunner 与 CommandLineRunner
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/889216.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号