zoukankan      html  css  js  c++  java
  • SpringBoot的常用特性

    常用功能特性

    SpringBoot应用启动入口

    package com.imooc.springboot.study;
    
    import org.springframework.boot.Banner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.WebApplicationType;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    
    /**
     * @author sunchangheng
     */
    @SpringBootApplication
    public class SpringBootStudyApplication {
        public static void main(String[] args) {
            // 1. 第一种: 通过静态run方法
    //            SpringApplication.run(SpringBootStudyApplication.class, args);
            
            // 2. 通过API调整应用行为
    //        SpringApplication app = new SpringApplication(SpringBootStudyApplication.class);
    //        app.setBannerMode(Banner.Mode.OFF);
    //        app.setWebApplicationType(WebApplicationType.NONE);
    //
    //        app.run(args);
            
            // 3. SpringApplicationBuilder Fluent API 链式调用
            new SpringApplicationBuilder(SpringBootStudyApplication.class).bannerMode(Banner.Mode.OFF)
                    .web(WebApplicationType.SERVLET).run(args);
            
        }
    }
    

    自动配置原理

    配置文件

    配置注入的方式

    # 配置文件application.yml
     
    # 自定义配置
    imooc:
      springboot:
        version: 2.1, 2.1.4
        name: study
    

    方式一

    package com.imooc.springboot.study.controller;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author sunchangheng
     */
    @Slf4j
    @RestController
    @RequestMapping("/springboot")
    public class TestController {
    
        @Value("${imooc.springboot.version}")
        private String version;
        
        @Value("${imooc.springboot.name}")
        private String name;
        
        @GetMapping("firstConfInject")
        public String firstConfInject() {
            log.info("version: {}, name: {}", version, name);
            return "ok";
        }
    }
    

    方式二

    1. 先写一个配置类

      package com.imooc.springboot.study.config;
      
      import lombok.Data;
      import org.springframework.boot.context.properties.ConfigurationProperties;
      import org.springframework.stereotype.Component;
      
      /**
       * SpringBoot 配置文件中前缀是imooc.springboot的配置
       *
       * @author sunchangheng
       */
      @Data
      @Component
      @ConfigurationProperties(prefix = "imooc.springboot")
      public class SpringBootConfig {
          
          /**
           * 版本
           */
          private String version;
          
          /**
           * 名字
           */
          private String name;
      }
      
    2. controller注入使用

      @Resource
      private final SpringBootConfig springBootConfig;
      
      @GetMapping("/secondConfigInject")
      public String secondConfigInject() {
          log.info("second: version: {} name: {}", springBootConfig.getVersion(), springBootConfig.getName());
          return "second ok";
      }
      

    定时任务

    1. 现在启动类上开启定时任务

    2. 配置定时任务类

      package com.imooc.springboot.study.schedule;
      
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.scheduling.annotation.Scheduled;
      import org.springframework.stereotype.Component;
      
      import java.time.LocalDateTime;
      import java.time.format.DateTimeFormatter;
      
      /**
       * SpringBoot 定时任务
       *
       * @author sunchangheng
       */
      @Slf4j
      @Component
      public class BootSchedule {
          
          private final DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH;mm;ss");
          
          /**
           * 上一次开始执行时间点之后3000毫秒之后再执行
           */
          @Scheduled(fixedRate = 3000)
          public void schedule01() {
              log.info("schedule01 -> {}", LocalDateTime.now().format(fmt));
          }
          
          /**
           * 上一次执行完毕时间点之后3000毫秒之后再执行
           */
          @Scheduled(fixedDelay = 3000)
          public void schedule02() {
              log.info("schedule02 -> {}", LocalDateTime.now().format(fmt));
          }
          
          /**
           * 第一次延迟2s之后执行, 之后按照上一次开始执行时间点之后3s之后再执行
           */
          @Scheduled(initialDelay = 2000, fixedRate = 3000)
          public void schedule03() {
              log.info("schedule03 -> {}", LocalDateTime.now().format(fmt));
          }
          
          /**
           * 每3s执行一次
           */
          @Scheduled(cron = "*/3 * * * * ?")
          public void schedule04() {
              log.info("schedule04 -> {}", LocalDateTime.now().format(fmt));
          }
          
      }
      

    异步任务

    1. 先在启动类启用

    2. 编写异步处理类

      package com.imooc.springboot.study.async;
      
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.scheduling.annotation.Async;
      import org.springframework.scheduling.annotation.AsyncResult;
      import org.springframework.stereotype.Service;
      
      import java.util.concurrent.Future;
      import java.util.concurrent.TimeUnit;
      
      /**
       * 异步处理服务
       *
       * @author sunchangheng
       */
      @Slf4j
      @Service
      public class AsyncService {
          
          @Async("getAsyncExecutor")
          public void asyncProcess() {
              log.info("async process task, current thread name -> {}", Thread.currentThread().getName());
              try {
                  TimeUnit.MILLISECONDS.sleep(2000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
          
          @Async("getAsyncExecutor")
          public Future<Integer> asyncProcessHasReturn() {
              log.info("async process task (has return), current thread name -> {}", Thread.currentThread().getName());
              try {
                  TimeUnit.MILLISECONDS.sleep(2000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              return new AsyncResult<>(100);
          }
      }
      

      @Async("getAsyncExecutor") 这里指定我们需要用到的线程池, 将会在下一个步骤配置

    3. 编写异步线程池配置

      package com.imooc.springboot.study.config;
      
      import com.alibaba.fastjson.JSON;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.scheduling.annotation.AsyncConfigurer;
      import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
      
      import java.lang.reflect.Method;
      import java.util.concurrent.Executor;
      import java.util.concurrent.ThreadPoolExecutor;
      
      /**
       * 自定义异步线程池配置
       *
       * @author sunchangheng
       */
      @Slf4j
      @Configuration
      public class AsyncConfig implements AsyncConfigurer {
          
          @Bean
          @Override
          public Executor getAsyncExecutor() {
              ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
              
              // 线程池核心的数量, 默认是1, 导致异步线程池无法被重用
              executor.setCorePoolSize(10);
              executor.setMaxPoolSize(20);
              executor.setQueueCapacity(20);
              executor.setKeepAliveSeconds(60);
              executor.setThreadNamePrefix("ImoocAsync_");
              
              // 是否等待所有线程执行完毕之后才去关闭线程池, 默认是false
              executor.setWaitForTasksToCompleteOnShutdown(true);
              // 和上面这个参数一起使用, 等待60s
              executor.setAwaitTerminationSeconds(60);
              
              // 拒绝策略
              // 就是线程池满了, 怎么处理的策略
              executor.setRejectedExecutionHandler(
                      // 直接抛出异常
                      new ThreadPoolExecutor.AbortPolicy());
              
              executor.initialize();
              
              return executor;
          }
          
          /**
           * 定义异步任务异常处理类 1. 没有返回值的异步任务, 的异常将会在这里抛出 2. 有返回值的异步任务, 异常将会抛出给上一层
           */
          @Override
          public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
              
              return new AsyncExceptionHandler();
          }
          
          static class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
              
              @Override
              public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
                  log.info("Async: {}, method: {}, param: {}",
                          throwable.getMessage(),
                          method.getName(),
                          JSON.toJSONString(objects));
                  
                  throwable.printStackTrace();
                  
                  // todo 发送邮件或者短信给相关负责人...
              }
          }
      }
      

      注意: getAsyncExecutor这个方法一定要加上@Bean

      单元测试

      package com.imooc.springboot.study.service;
      
      import com.imooc.springboot.study.async.AsyncService;
      import lombok.extern.slf4j.Slf4j;
      import org.junit.Test;
      import org.junit.runner.RunWith;
      import org.springframework.boot.test.context.SpringBootTest;
      import org.springframework.test.context.junit4.SpringRunner;
      
      import javax.annotation.Resource;
      import java.util.concurrent.Future;
      
      @Slf4j
      @SpringBootTest
      @RunWith(SpringRunner.class)
      public class AsyncServiceTest {
          @Resource
          private AsyncService asyncService;
          
          @Test
          public void testAsyncProcess() {
              asyncService.asyncProcess();
              log.info("testAsyncProcess end...");
          }
          
          @Test
          public void testAsyncProcessHasReturn() throws Exception {
              long start = System.currentTimeMillis();
              Future<Integer> result = asyncService.asyncProcessHasReturn();
              log.info("异步任务返回值: {}", result.get());
              log.info("测试用例执行了: {} ms", System.currentTimeMillis() - start);
          }
      }
      

      注意一定要加这两个注解: @SpringBootTest @RunWith(SpringRunner.class)

      开机启动

      方式一

      package com.imooc.springboot.study.runer;
      
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.boot.ApplicationArguments;
      import org.springframework.boot.ApplicationRunner;
      import org.springframework.core.annotation.Order;
      import org.springframework.stereotype.Component;
      
      /**
       * 1. SpringBoot 开机启动
       * @author sunchangheng
       */
      @Order(2)
      @Slf4j
      @Component
      public class BootApplicationRunner implements ApplicationRunner {
          
          @Override
          public void run(ApplicationArguments args) throws Exception {
              log.info("this is BootApplicationRunner ...");
          }
      }
      

      方式二

      package com.imooc.springboot.study.runer;
      
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.boot.CommandLineRunner;
      import org.springframework.core.annotation.Order;
      import org.springframework.stereotype.Component;
      
      /**
       * 2. SpringBoot开机启动
       * @author sunchangheng
       */
      @Order(1)
      @Slf4j
      @Component
      public class BootCommandLineRunner implements CommandLineRunner {
          
          
          @Override
          public void run(String... args) throws Exception {
              log.info("this is BootCommandLineRunner ...");
          }
      }
      

      注意

      1. 默认ApplicationRunner 的启动优先级大于CommandLineRunner
      2. 可以使用Order 定义启动顺序, 值越小优先级越高

      Json使用技巧

      Java 实体类

      package com.imooc.springboot.study.vo;
      
      import com.fasterxml.jackson.annotation.JsonFormat;
      import com.fasterxml.jackson.annotation.JsonIgnore;
      import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
      import com.fasterxml.jackson.annotation.JsonProperty;
      import lombok.AllArgsConstructor;
      import lombok.Builder;
      import lombok.Data;
      import lombok.NoArgsConstructor;
      
      import java.util.Date;
      
      /**
       * 用户
       * @author sunchangheng
       */
      @Data
      @NoArgsConstructor
      @AllArgsConstructor
      @Builder
      @JsonIgnoreProperties({"remark", "desc"})
      public class Imoocer {
          private String name;
          
          private Integer age;
          
          @JsonIgnore
          private String address;
          
          @JsonProperty("rt")
          @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
          private Date registerTime;
          
          private String remark;
          
          private String desc;
      
      }
      

      注意

      JsonIgnoreProperties  # 在类上注释, 可以忽略多个不想序列化的字段
      JsonProperty  # 序列化时, 会将registerTime 改变成 rt
      JsonIgnore  # 注释在属性上, 当前属性将不会被序列化
      JsonFormat  # Date的序列化格式
      

      Json全局配置

      package com.imooc.springboot.study.config;
      
      import com.fasterxml.jackson.annotation.JsonInclude;
      import com.fasterxml.jackson.databind.ObjectMapper;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      
      import java.text.SimpleDateFormat;
      
      /**
       * Json的配置类
       * @author sunchangheng
       */
      @Configuration
      public class JacksonConfig {
          
          @Bean
          public ObjectMapper getObjectMapper() {
              ObjectMapper mapper = new ObjectMapper();
              // 空值不做序列化处理
              mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
              // 序列化的时间格式
              mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
              return mapper;
          }
      }
      

      controller序列化与反序列化测试

      package com.imooc.springboot.study.controller;
      
      import com.fasterxml.jackson.core.JsonProcessingException;
      import com.fasterxml.jackson.databind.ObjectMapper;
      import com.imooc.springboot.study.config.SpringBootConfig;
      import com.imooc.springboot.study.vo.Imoocer;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import javax.annotation.Resource;
      import java.io.IOException;
      import java.util.Date;
      
      /**
       * @author sunchangheng
       */
      @Slf4j
      @RestController
      @RequestMapping("/springboot")
      public class TestController     
          @Resource
          private ObjectMapper mapper
          
          /**
           * 功能描述: Json序列化与反序列化测试
           * 127.0.0.1:8000/imooc/springboot/jackson
           */
          @GetMapping("/jackson")
          public Imoocer jackson() throws IOException {
              Imoocer imoocer = Imoocer.builder().name("qinyi").age(19).remark("hello world").desc("什么")
                      .registerTime(new Date()).build();
          
              // 序列化: object->json
              String jsonImoocer = mapper.writeValueAsString(imoocer);
          
              // 反序列化: json->object
              return mapper.readValue(jsonImoocer, Imoocer.class);
          }
      }
      

      Actuator监控

      // /actuator/info 默认返回空
      // 可以在配置文件配置info
      
      

      简单使用

      <!-- Actuator监控 -->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
      

      配置文件

      # Actuator监控相关
      management:
        endpoint:
          shutdown:
            enabled: true  # 最特殊的控制断点, 远程关闭应用程序的断点, 比较危险, 一般不打开
      
        endpoints:
          web:
            exposure:
              include:  "*" # 打开所有断点
      
      # /imooc/actuator
      # http://127.0.0.1:8000/imooc/actuator/health
      # http://127.0.0.1:8000/imooc/actuator/info
      
      info:
        app:
          name: imooc-springboot-study
          groupId: com.imooc.springboot.study
          version: 1.0-SNAPSHOT
      

      自定义监控端点

      1. 自定义端点

        package com.imooc.springboot.study.endpoint;
        
        import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
        import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
        import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
        
        import java.text.SimpleDateFormat;
        import java.util.Date;
        import java.util.HashMap;
        import java.util.Map;
        
        /**
         * 自定义事件端点 127.0.0.1:8000/imooc/actuator/datetime
         *
         * @author sunchangheng
         */
        @Endpoint(id = "datetime")
        public class DateTimeEndpoint {
            
            private String fmt = "yyyy-MM-dd HH:mm:ss";
            
            /**
             * 功能描述: 用来显示监控指标
             * get   http://127.0.0.1:8000/imooc/actuator/datetime
             */
            @ReadOperation
            public Map<String, Object> info() {
                Map<String, Object> info = new HashMap<>(10);
                info.put("name", "sch");
                info.put("age", 19);
                info.put("dt", new SimpleDateFormat(fmt).format(new Date()));
                return info;
            }
            
            /**
             * 功能描述: 动态更改监控指标
             * post  http://127.0.0.1:8000/imooc/actuator/datetime
             */
            @WriteOperation
            public void setFormat(String format) {
                this.fmt = format;
            }
        }
        
      2. 启用自定义配置的端点

        package com.imooc.springboot.study.endpoint;
        
        import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
        import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;
        
        /**
         * 自定义端点配置类
         *
         * @author sunchangheng
         */
        @Configuration
        public class DateTimeEndpointConfig {
            
            @Bean
            @ConditionalOnMissingBean
            @ConditionalOnEnabledEndpoint
            public DateTimeEndpoint dateTimeEndpoint() {
                return new DateTimeEndpoint();
            }
        }
        

        注意: 需要在配置文件中打开所有端点

      自定义 Starter

      • 新建一个starter项目
        1. 依赖

          <dependencies>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-configuration-processor</artifactId>
                  <version>2.1.4.RELEASE</version>
              </dependency>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-autoconfigure</artifactId>
                  <version>2.1.4.RELEASE</version>
              </dependency>
          </dependencies>
          
        2. 创建service

          1. 接口

            package com.imooc.springboot.service;
            
            import java.util.List;
            
            /**
             * @author sunchangheng
             */
            public interface ISplictService {
                
                /**
                 * 功能描述: 分割字符串
                 * @param str 将要分割的字符串
                 * @return 字符串列表
                 */
                List<String> split(String str);
            
            }
            
          2. 实现

            package com.imooc.springboot.service.impl;
            
            import com.imooc.springboot.service.ISplictService;
            import org.springframework.util.StringUtils;
            
            import java.util.List;
            import java.util.stream.Collectors;
            import java.util.stream.Stream;
            
            /**
             * @author sunchangheng
             */
            public class SplictServiceImpl implements ISplictService {
                
                @SuppressWarnings("all")
                @Override
                public List<String> split(String str) {
                    return Stream.of(StringUtils.split(str, ",")).collect(Collectors.toList());
                }
            }
            
        3. 配置自动注入

          package com.imooc.springboot.configure;
          
          import com.imooc.springboot.service.ISplictService;
          import com.imooc.springboot.service.impl.SplictServiceImpl;
          import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
          import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;
          
          /**
           * @author sunchangheng
           */
          @Configuration
          @ConditionalOnClass({ISplictService.class, SplictServiceImpl.class})
          public class SplictAutoConfigure {
              
              @Bean
              @ConditionalOnMissingBean
              ISplictService starterService() {
                  return new SplictServiceImpl();
              }
          }
          
        4. 配置meta-inf

          org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.imooc.springboot.configure.SplictAutoConfigure
          
        5. maven 打包到本地 mvn install

        6. 最后就可以在其他项目引入使用了

      • 在其他项目引入使用
        1. 引入依赖

          <dependency>
              <groupId>com.imooc.springboot</groupId>
              <artifactId>split-spring-boot-starter</artifactId>
              <version>1.0-SNAPSHOT</version>
          </dependency>
          
        2. 使用测试用例测试

          package com.imooc.springboot.study.service;
          
          import com.alibaba.fastjson.JSON;
          import com.imooc.springboot.service.ISplictService;
          import com.imooc.springboot.study.config.SpringBootConfig;
          import lombok.extern.slf4j.Slf4j;
          import org.junit.Test;
          import org.junit.runner.RunWith;
          import org.springframework.boot.test.context.SpringBootTest;
          import org.springframework.test.context.junit4.SpringRunner;
          
          import javax.annotation.Resource;
          
          @Slf4j
          @SpringBootTest
          @RunWith(SpringRunner.class)
          public class SplictServiceTest {
              @Resource
              private ISplictService splictService;
              
              @Resource
              private SpringBootConfig springBootConfig;
              
              @Test
              public void testSplictVersion() {
                  log.info("splict version: {}", JSON.toJSONString(splictService.split(springBootConfig.getVersion())));
              }
          }
          

      管理 SpringBoot 应用

      # 打包到target目录
      mvn clean package -Dmaven.test.skip=true -U
      

      启动脚本

      # start.sh
      #!/usr/bin/env bash
      nohup java -jar imooc-springboot-study.jar &
      

      停止脚本

      #!/usr/bin/env bash
      
      pid=`ps -ef | grep imooc-springboot-study.jar | grep -v grep | awk '{print $2}'`
      
      if [[ -z "${pid}"]]
      then
        echo application is already stopped
      else
        echo kill ${pid}
        kill -9 ${pid}
      fi
      
  • 相关阅读:
    739. Daily Temperatures
    556. Next Greater Element III
    1078. Occurrences After Bigram
    1053. Previous Permutation With One Swap
    565. Array Nesting
    1052. Grumpy Bookstore Owner
    1051. Height Checker
    数据库入门及SQL基本语法
    ISCSI的概念
    配置一个IP SAN 存储服务器
  • 原文地址:https://www.cnblogs.com/sunch/p/15088095.html
Copyright © 2011-2022 走看看