zoukankan      html  css  js  c++  java
  • 20201209 Spring Boot

    SpringBoot 基础回顾

    • Spring Boot 是所有基于 Spring 开发的项目的起点。Spring Boot 的设计是为了让你尽可能快的跑起来 Spring 应用程序并且尽可能减少你的配置文件。

    • 约定优于配置(Convention over Configuration),又称按约定编程,是一种软件设计范式

    • Spring Boot 在 Spring 的基础上做了两项改进:

      • 依赖管理
        • starter 约定
        • 依赖版本控制
      • 自动配置
    • Spring Initializr

    单元测试

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
    
    @RunWith(SpringRunner.class)  //测试启动器,并加载spring boot测试注解
    @SpringBootTest //标记该类为spring boot单元测试类,并加载项目的applicationContext上下文环境
    class Springboot01DemoApplicationTests {
    
        //入门案例测试
        @Autowired
        private HelloController helloController;
    
        @Test
        void contextLoad1() {
            String demo = helloController.demo();
            System.out.println(demo);
        }
    }
    

    热部署

    1. 增加依赖
    <!-- 引入热部署依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
    
    1. 勾选 File | Settings | Build, Execution, Deployment | Compiler | Build project automatically
    2. 快捷键 Ctrl+Shift+Alt+/ ,选择 Registry,勾选 compiler.automake.allow.when.app.running
    3. Ctrl+F9 触发 Build Project
    4. 重启生效

    配置相关

    @ConfigurationProperties 添加配置提示

    1. POM

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-configuration-processor</artifactId>
          <optional>true</optional>
      </dependency>
      
    2. 使用注解 @ConfigurationProperties

      @ConfigurationProperties(prefix = "person") //将配置文件中以person开头的属性注入到该类中
      public class Person {
          private int id; //id
          private String name; //名称
          private List hobby; //爱好
          private String[] family; //家庭成员
          private Map map;
          private Pet pet; //宠物
      }
      
    3. Ctrl+F9,Build Project

    Properties、Yaml 配置写法
    person.id=10
    person.name=张三
    person.hobby=h1,h2,h3
    person.family=f1,f2,f3
    person.map.k1=v1
    person.map.k2=v2
    person.pet.type=dog
    person.pet.name=旺财
    
    person:
      id: 12
      name: 李四
      hobby: [h1,h2,h3]
      family: [f1,f2]
      map: {k1: v1, k2: v2}
      pet: {type: dog, name: 旺财}
    
    person:
      id: 12
      name: 李四
      hobby:
        - h1
        - h2
        - h3
      family:
        f1
        f2
      map:
        k1: v1
        k2: v2
        k3: v3
        "[/key1]": v4
      pet:
        type: dog
        name: ndog
    

    绑定 Map 属性时,如果 key 包含除小写字母、数字字符或 - 之外的任何内容,则需要使用方括号表示法,以便保留原始值。如果键没有被 [] 包围,则所有其他字符被删除。例如:

    map:
      "[/key1]": value1
      "[/key2]": value2
      /key3: value3
    

    Map具有 /key1/key2key3 作为映射中的键。

    @Value 属性注入

    @Value("${person.id:20}")
    

    @PropertySource 加载配置文件

    将属性文件作为 PropertySource 加载到 Spring 容器中

    @Data
    @Component
    @PropertySource("classpath:testa.properties")  //配置自定义配置文件的名称及位置
    @ConfigurationProperties(prefix = "test")
    public class MyProperties {
    
        private int id;
        private String name;
    
    }
    

    @Configuration 编写自定义配置类

    • 类似于声明了一个 XML 配置文件

    随机数设置

    • org.springframework.boot.env.RandomValuePropertySource
    # 配置随机值
    my.secret=${random.value}
    # 配置随机整数
    my.number=${random.int}
    # 配置随机long类型数
    my.bignumber=${random.long}
    # 配置随机uuid类型数
    my.uuid=${random.uuid}
    # 配置小于10的随机整数
    my.number.less.than.ten=${random.int(10)}
    # 配置范围在[1024,65536]之间的随机整数
    my.number.in.range=${random.int[1024,65536]}
    

    参数间引用

    test.v1=v1
    test.v2=${test.v1} is v2
    test.v3=${user.country} is v2
    

    SpringBoot 原理深入及源码剖析

    依赖管理

    Spring Boot 项目在 POM 中需要继承 spring-boot-starter-parent

        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.2.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    

    spring-boot-starter-parent-2.2.2.RELEASE.pom 指定了继承 spring-boot-dependencies

      <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath>../../spring-boot-dependencies</relativePath>
      </parent>
    

    spring-boot-dependencies-2.2.2.RELEASE.pom 中,定义了版本控制

    <properties>
        ......
        <wsdl4j.version>1.6.3</wsdl4j.version>
        ......
    </properties>
    </dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot</artifactId>
                <version>2.2.2.RELEASE</version>
            </dependency>
            ......
            ......
            <dependency>
                <groupId>wsdl4j</groupId>
                <artifactId>wsdl4j</artifactId>
                <version>${wsdl4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    

    自动配置(启动流程)

    SpringBoot 将 spring.factoriesorg.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的值加入容器的过程:

    • org.springframework.boot.autoconfigure.SpringBootApplication
      • org.springframework.boot.autoconfigure.EnableAutoConfiguration
        • org.springframework.boot.autoconfigure.AutoConfigurationImportSelector
          • org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports
            • org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#getAutoConfigurationMetadata
              • org.springframework.boot.autoconfigure.AutoConfigurationMetadataLoader#loadMetadata(java.lang.ClassLoader)
                • org.springframework.boot.autoconfigure.AutoConfigurationMetadataLoader#PATH
                  • META-INF/spring-autoconfigure-metadata.properties
                • org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getCandidateConfigurations
                  • org.springframework.core.io.support.SpringFactoriesLoader#loadSpringFactories
                    • org.springframework.core.io.support.SpringFactoriesLoader#FACTORIES_RESOURCE_LOCATION
                      • META-INF/spring.factories
                • org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#filter

    @EnableAutoConfiguration 就是从 classpath 中搜寻 META-INF/spring.factories 配置文件,并将其中
    org.springframework.boot.autoconfigure.EnableutoConfiguration 对应的配置项通过反射(Java
    Refletion)实例化为对应的标注了 @Configuration 的 JavaConfig 形式的配置类,并加载到 IOC 容器中

    实例分析:

    • mybatis-spring-boot-starter 为例,依赖 mybatis-spring-boot-autoconfigure,这个 jar 包内存在 META-INF/spring.factories,内容为:

      # Auto Configure
      org.springframework.boot.autoconfigure.EnableAutoConfiguration=
      org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,
      org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
      

    自定义 Stater

    • starter 是 SpringBoot 非常重要的一部分,可以理解为一个可拔插式的插件,正是这些 starter 使得使用某个功能的开发者不需要关注各种依赖库的处理,不需要具体的配置信息,由 Spring Boot 自动通过 classpath 路径下的类发现需要的 Bean ,并织入相应的 Bean 。
    • SpringBoot 提供的 starter 以 spring-boot-starter-xxx 的方式命名的。官方建议自定义的 starter 使用
      xxx-spring-boot-starter 命名规则。
    1. POM

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <parent>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-parent</artifactId>
              <version>2.2.2.RELEASE</version>
              <relativePath/> <!-- lookup parent from repository -->
          </parent>
      
          <groupId>com.lagou.starter</groupId>
          <artifactId>mystarter-spring-boot-starter</artifactId>
          <version>1.0-SNAPSHOT</version>
      
      
          <dependencies>
      
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-autoconfigure</artifactId>
                  <version>2.2.2.RELEASE</version>
              </dependency>
      
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
                  <optional>true</optional>
              </dependency>
      
          </dependencies>
      
      
      
      </project>
      
    2. META-INF/spring.factories

      org.springframework.boot.autoconfigure.EnableAutoConfiguration=
      com.lagou.starter.mystarter.MyAutoConfiguration
      
    3. MyAutoConfiguration.java

      @ConditionalOnMissingBean({MySimpleBean.class})
      @Configuration
      public class MyAutoConfiguration {
          @Bean
          public MySimpleBean mySimpleBean() {
              return new MySimpleBean();
          }
      }
      
    4. POM,引用自定义 starter

      <dependency>
          <groupId>com.lagou.starter</groupId>
          <artifactId>mystarter-spring-boot-starter</artifactId>
          <version>1.0-SNAPSHOT</version>
      </dependency>
      

    执行原理

    分析启动代码:

    public static void main(String[] args) {
        SpringApplication.run(Springboot01DemoApplication.class, args);
    }
    
    • org.springframework.boot.SpringApplication#run

    如果 pom 中有以下依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
    

    Main 线程被关闭,启动新的线程,基于监听器 RestartApplicationListener

    • org.springframework.boot.devtools.restart.Restarter#immediateRestart

    SpringBoot 数据访问

    • SpringData 是 Spring 提供的一个用于简化数据库访问、支持云服务的开源框架。它是一个伞形项目,包含了大量关系型数据库及非关系型数据库的数据访问解决方案,其设计目的是使我们可以快速且简单地使用各种数据访问技术。

    • Spring Boot 默认采用整合 SpringData 的方式统一处理数据访问层,通过添加大量自动配置,引入各种数据访问模板 xxxTemplate 以及统一的 Repository 接口,从而达到简化数据访问层的操作。

    • Spring Data 提供了多种类型数据库支持,对支持的的数据库进行了整合管理,提供了各种依赖启动器,接下来,通过一张表罗列提供的常见数据库依赖启动器

      名称 描述
      spring-boot-starter-data-jpa 使用 Spring Data JPA 与 Hibernate
      spring-boot-starter-data mongodb 使用 MongoDB 和 Spring Data MongoDB
      spring-boot-starter-data-neo4j 使用 Neo4j 图数据库和 Spring Data Neo4j
      spring-boot-starter-data-redis 使用 Redis 键值数据存储与 Spring Data Redis

    Spring Boot 整合 MyBatis

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.1</version>
    </dependency>
    
    • @Mapper 注解表示该类是一个 MyBatis 接口文件,并保证能够被 Spring Boot 自动扫描到 Spring 容器中
    • 对应的接口类上添加了 @Mapper 注解,如果编写的 Mapper 接口过多时,需要重复为每一个接口文件添加 @Mapper 注解
    • 为了解决这种麻烦,可以直接在 Spring Boot 项目启动类上添加 @MapperScan("xxx") 注解,不需要再逐个添加 @Mapper 注解,@MapperScan("xxx") 注解的作用和 @Mapper 注解类似,但是它必须指定需要扫描的具体包名

    @MapperScan 将扫描到的接口转换成 org.mybatis.spring.mapper.MapperFactoryBean 的过程:

    • org.mybatis.spring.annotation.MapperScan 注解引入了 MapperScannerRegistrar

    • 引入 MapperScannerConfigurer,是一个 BeanDefinitionRegistryPostProcessor

    • 触发生命周期,org.mybatis.spring.mapper.MapperScannerConfigurer#postProcessBeanDefinitionRegistry

      • org.mybatis.spring.mapper.ClassPathMapperScanner#doScan
        • org.mybatis.spring.mapper.ClassPathMapperScanner#processBeanDefinitions

    mybatis-spring-boot-starter 自动配置类:

    • org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

    Spring Boot 整合 JPA

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    @Data
    @Entity
    @Table(name = "t_comment")
    public class Comment {
    
        @Id //表明映射主键id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Integer id;  //评论id
        private String content; //评论内容
        private String author; //评论作者
        @Column(name = "a_id")
        private Integer aId; //外键:表示当前这条评论是属于那篇文章
    }
    
    public interface CommentRepository extends JpaRepository<Comment, Integer> {
    }
    
    //测试整合JPA
    @Autowired
    private CommentRepository commentRepository;
    
    @Test
    public void selectComment() {
        Optional<Comment> byId = commentRepository.findById(1);
        if (byId.isPresent()) {
            System.out.println(byId.get());
        }
    }
    

    相关自动配置类:

    • org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
    • org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration

    Spring Boot 整合 Redis

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
    #redis服务器地址
    spring.redis.host=127.0.0.1
    #redis服务器连接端口
    spring.redis.port=6379
    #redis服务器连接密码
    spring.redis.password=
    
    @Data
    @RedisHash(value = "persons") //指定实体类对象在redis中的存储空间
    public class Person {
    
        @Id // 用来标识实体类主键  字符串形式的hashkey标识唯一的实体类对象id
        private String id;
        @Indexed // 用来标识对应属性在redis中生成二级索引
        private String firstname;
        @Indexed
        private String lastname;
        private Address address;
    
    }
    
    public interface PersonRepository extends CrudRepository<Person,String> {
    
        // 根据城市信息查询对应的人
        List<Person> findByAddress_City(String name);
    }
    
    //测试整合redis
    @Autowired
    private PersonRepository personRepository;
    
    @Test
    public void savePerson(){
        Person person = new Person();
        person.setFirstname("张");
        person.setLastname("三");
    
        Address address = new Address();
        address.setCity("北京");
        address.setCountry("中国");
        person.setAddress(address);
    
        // 向redis数据库中添加了数据
        personRepository.save(person);
    
    }
    
    @Test
    public void selectPerson(){
        List<Person> list = personRepository.findByAddress_City("北京");
        for (Person person : list) {
            System.out.println(person);
        }
    
    
    }
    

    SpringBoot 视图技术

    • 前端模板引擎技术的出现,使前端开发人员无需关注后端业务的具体实现,只关注自己页面的呈现效果即可,并且解决了前端代码错综复杂的问题、实现了前后端分离开发。Spring Boot框架对很多常用的模板引擎技术(如:FreeMarker、Thymeleaf、Mustache等)提供了整合支持

    • Spring Boot不太支持常用的JSP模板,并且没有提供对应的整合配置,这是因为使用嵌入式Servlet容器的Spring Boot应用程序对于JSP模板存在一些限制 :

      • Spring Boot默认使用嵌入式Servlet容器以JAR包方式进行项目打包部署,这种JAR包方式不支持JSP模板。
      • 如果使用Undertow嵌入式容器部署Spring Boot项目,也不支持JSP模板。
      • Spring Boot默认提供了一个处理请求路径“/error”的统一错误处理器,返回具体的异常信息。使用JSP模板时,无法对默认的错误处理器进行覆盖,只能根据Spring Boot要求在指定位置定制错误页面。

    Thymeleaf

    SpringBoot 缓存管理

    默认缓存管理

    • Spring 框架支持透明地向应用程序添加缓存对缓存进行管理,其管理缓存的核心是将缓存应用于操作数据的方法,从而减少操作数据的执行次数,同时不会对程序本身造成任何干扰。

    • Spring Boot 继承了 Spring 框架的缓存管理功能,通过使用 @EnableCaching 注解开启基于注解的缓存支持,Spring Boot 就可以启动缓存管理的自动化配置。

    • @EnableCaching

    • @Cacheable

      属性名 说明
      value/cacheNames 指定缓存空间的名称,必配属性。这两个属性二选一使用
      key 指定缓存数据的key,默认使用方法参数值,可以使用SpEL表达式
      keyGenerator 指定缓存数据的key的生成器,与key属性二选一使用
      cacheManager 指定缓存管理器
      cacheResolver 指定缓存解析器,与cacheManager属性二选一使用
      condition 指定在符合某条件下,进行数据缓存
      unless 指定在符合某条件下,不进行数据缓存
      sync 指定是否使用异步缓存。默认false
    • @CachePut

    • @CacheEvict

    自定义 Redis 缓存序列化机制

    自定义 JSON 格式的数据序列化方式进行数据缓存管理:

    • 基于 API 的 Redis 缓存实现是使用 RedisTemplate 模板进行数据缓存操作的
      • 使用 RedisTemplate 手动控制,不推荐
    • 基于注解的 Redis 缓存需要自定义 RedisCacheManager
    • 两者互不相关
    @Configuration
    public class RedisConfig {
    
    
        @Bean
        public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<Object, Object> template = new RedisTemplate<>();
            template.setConnectionFactory(redisConnectionFactory);
    
            // 创建JSON格式序列化对象,对缓存数据的key和value进行转换
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    
    
            // 解决查询缓存转换异常的问题
            ObjectMapper om = new ObjectMapper();
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            // om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
    
            jackson2JsonRedisSerializer.setObjectMapper(om);
    
            //设置redisTemplate模板API的序列化方式为json
            template.setDefaultSerializer(jackson2JsonRedisSerializer);
    
    
            return template;
        }
    
    
        @Bean
        public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
            // 分别创建String和JSON格式序列化对象,对缓存数据key和value进行转换
            RedisSerializer<String> strSerializer = new StringRedisSerializer();
            Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
    
            // 解决查询缓存转换异常的问题
            ObjectMapper om = new ObjectMapper();
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            // om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
            jacksonSeial.setObjectMapper(om);
    
            // 定制缓存数据序列化方式及时效
            RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(1)).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(strSerializer)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSeial)).disableCachingNullValues();
            RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).build();
            return cacheManager;
        }
    
    
    }
    

    参考资料

  • 相关阅读:
    github国内加速
    js 关闭MediaDevices.getUserMedia()
    windows server 安装 mysql + nondejs连接mysql
    sql常用语法大全
    当小程序的flex布局遇到button时,justify-content不起作用的原因及解决方案
    c# 使用Sharp7对PLC读写操作
    c#中引用c++动态库
    Python+Django
    python+pycharm+Django报错
    Dapper支持各类数据库(mysql,mssql,FireBird,Oracle)
  • 原文地址:https://www.cnblogs.com/huangwenjie/p/14110929.html
Copyright © 2011-2022 走看看