• Welcome to the world's largest Chinese hacker forum

    Welcome to the world's largest Chinese hacker forum, our forum registration is open! You can now register for technical communication with us, this is a free and open to the world of the BBS, we founded the purpose for the study of network security, please don't release business of black/grey, or on the BBS posts, to seek help hacker if violations, we will permanently frozen your IP and account, thank you for your cooperation. Hacker attack and defense cracking or network Security

    business please click here: Creation Security  From CNHACKTEAM

Recommended Posts

1、SpringBoot starter机制

SpringBoot中的Starter是一个非常重要的机构,它可以抛弃以前复杂的配置,集成到starter中。用户只需要在maven中引入starter依赖即可。

SpringBoot可以自动扫描要加载的信息,并启动相应的默认配置。Starter让我们摆脱了各种依赖库,需要配置各种信息。

SpringBoot会通过classpath路径下的类自动发现所需的Bean,并将其注册到IOC容器中。SpringBoot提供了一个spring-boot-starter依赖模块来开发日常企业应用程序的各种场景。

这些依赖模块都遵循常规的默认配置,并且允许我们调整这些配置,也就是遵循“常规大于配置”的理念。

2、为什么要自定义starter

在我们的日常开发工作中,经常会有一些独立于业务之外的配置模块。我们经常将它们放在一个特定的包中,然后如果另一个项目需要重用这个函数,我们需要将代码硬拷贝到另一个项目中。

重新整合极其麻烦。如果我们把这些可以独立于业务代码的工作配置模块打包到starter中,那么重用的时候只需要在pom中引用就可以了。SpringBoot为我们完成自动组装,简直不要太爽。

3、自定义starter的命名规则

SpringBoot提供的启动器以spring-boot-starter-xxx命名。官方定制启动器推荐使用xxx-spring-boot-starter命名规则。来区分SpringBoot生态系统提供的启动器。

4、代码地址

https://gitee.com/tenic/demo-spring-boot-starter.git

5、代码具体实现

目录结构如下图所示,其中demo-spring-boot-starter是父项目,properties-spring-boot-starter和interceptor-spring-boot-starter是我们今天要实现的两个自定义启动器。

Test-spring-boot-starter是我们的测试项目。

tlsen4ycjsx5225.png

创建演示-弹簧-启动-启动器

我们创建一个空的springboot项目,我们依赖的版本是2.3.7.RELEASE,具体的POM文件依赖内容如下面的代码所示:

?xml版本='1.0 '编码='UTF-8 '?

项目xmlns=' http://maven . Apache . org/POM/4 . 0 . 0 '

xmlns : xsi=' http://www . w3 . org/2001/XML schema-instance '

xsi : schema location=' http://maven . Apache . org/POM/4 . 0 . 0 http://maven.apache.org/xsd/maven-4.0.0.xsd'

型号版本4 . 0 . 0/型号版本

包装包装/包装

!-子模块工程-

模块

模块属性-弹簧-启动-启动器/模块

模块测试-弹簧-启动-启动器/模块

模块连接器-弹簧-启动-启动器/模块

/模块

父母

groupIdorg.springframework.boot/groupId

artifactId spring-boot-starter-parent/artifactId

<version>2.3.7.RELEASE</version> </parent> <groupId>com.demo</groupId> <artifactId>demo-spring-boot-starter</artifactId> <version>0.0.1-RELEASE</version> <name>demo-spring-boot-starter</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> </dependencies> </project> properties-spring-boot-starter创建,
  • 我们这里创建一个父工程的子模块,具体模块划分如下图所示

    cizuij0g0dq5226.png

  • 因为我们依赖父工程,且父工程已经依赖了我们需要的基本的jar包,所以我们的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>demo-spring-boot-starter</artifactId>
              <groupId>com.demo</groupId>
              <version>0.0.1-RELEASE</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
          <artifactId>properties-spring-boot-starter</artifactId>
          <packaging>jar</packaging>
      </project>
    
  • 创建一个Properties相关的类,用来使用配置相关的信息

      package com.tenic.springboot.properties;
      import org.springframework.boot.context.properties.ConfigurationProperties;
      @ConfigurationProperties(prefix = "tenic")
      public class CustomerProperties {
          private String username;
          private String password;
          private String driver;
          private String url;
          // ... 省略 有参,无参 构造函数 getter/setter方法 ...
      }
    
  • 创建一个使用到Properties信息的一个类,比如我们创建一个工厂类ServiceFactory

      package com.tenic.springboot.service;
      import com.tenic.springboot.properties.CustomerProperties;
      public class ServiceFactory {
          public ServiceFactory(CustomerProperties customerProperties) {
              System.out.println(customerProperties.toString());
          }
      }
    
  • 创建一个自动装配的类,将我们上边的ServiceFactory生成Bean 放入到我们的Spring 容器里面来

      package com.tenic.springboot.config;
      import com.tenic.springboot.properties.CustomerProperties;
      import com.tenic.springboot.service.ServiceFactory;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.boot.context.properties.EnableConfigurationProperties;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      @Configuration
      @EnableConfigurationProperties({CustomerProperties.class})
      public class CustomerPropertiesAutoConfiguration {
         @Autowired
         CustomerProperties properties;
         @Bean
         public ServiceFactory getServiceFactory(){
             return new ServiceFactory(properties);
         }
      }
    
  • 在resource目录下创建一个META-INF/spring.factories的文件,文件的内容就是我们要自动装配的具体的信息

      org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
        com.tenic.springboot.config.CustomerPropertiesAutoConfiguration
    
  • 在resource目录下创建一个application.yml的文件,配置上我们需要的配置信息

      server:
        port: 9091
      tenic:
        username: tenic
        password: 123456
        driver: com.tenic.springboot
        url: www.cnblogs.com/tenic
    
  • 启动模块的启动类, 可以看到控制台上打印出来了我们配置的具体信息,说明已经将具体的配置信息自动装配进去了
    rgfvshccocc5227.png

interceptor-spring-boot-starter 创建
  • 我们这里来实现一个对接口调用统计时间的一个starter, 具体我们是使用到了拦截器的机制,在执行前确定是啥时候开始,执行后确定啥时候结束,统计花费时长。
    我们也同样创建一个父工程的子模块,具体的目录结构如下图所示
    xdytx5xfw115228.png
  • 具体的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>demo-spring-boot-starter</artifactId>
              <groupId>com.demo</groupId>
              <version>0.0.1-RELEASE</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
          <packaging>jar</packaging>
          <artifactId>interceptor-spring-boot-starter</artifactId>
      </project>
    
  • 我们创建一个注解,帮我们在相应的方法上打上标记
      package com.tenic.springboot.annotion;
      import java.lang.annotation.*;
      @Target(ElementType.METHOD)
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      @Inherited
      public @interface TenicLog {
          String desc() default "";
      }
    
  • 创建自定义的拦截器,在拦截器中记录上我们请求的地址,接口,花费时长等信息
      package com.tenic.springboot.interceptor;
      import com.tenic.springboot.annotion.TenicLog;
      import org.springframework.web.method.HandlerMethod;
      import org.springframework.web.servlet.ModelAndView;
      import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      public class CustomerInterceptor extends HandlerInterceptorAdapter {
          private final ThreadLocal<Long> threadLocal = new ThreadLocal<>();
          @Override
          public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
              HandlerMethod handlerMethod = (HandlerMethod) handler;
              TenicLog tenicLog = handlerMethod.getMethodAnnotation(TenicLog.class);
              if(tenicLog!=null) {
                  threadLocal.set(System.currentTimeMillis());
              }
              return true;
          }
          @Override
          public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
              HandlerMethod handlerMethod = (HandlerMethod) handler;
              TenicLog tenicLog = handlerMethod.getMethodAnnotation(TenicLog.class);
              if(tenicLog!=null){
                  Long costTime = System.currentTimeMillis()-threadLocal.get();
                  String desc = tenicLog.desc();
                  String name = handlerMethod.getMethod().getDeclaringClass()+" " +handlerMethod.getMethod().getName();
                  StringBuffer requestURL = request.getRequestURL();
                  System.out.println("请求地址为:"+ requestURL +" 方法是:"+ name +" 描述信息是:"+ desc +" 总耗时:" + costTime + "ms");
              }
          }
      }
    
  • 创建自动装配类,并将拦截器注册到容器中
      package com.tenic.springboot.config;
      import com.tenic.springboot.interceptor.CustomerInterceptor;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
      import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
      @Configuration
      public class InterceptorAutoConfiguration implements WebMvcConfigurer {
          @Override
          public void addInterceptors(InterceptorRegistry registry) {
              registry.addInterceptor(new CustomerInterceptor());
          }
      }
    
  • 在resource目录下创建一个application.yml的文件,配置上我们需要的配置信息
      server:
        port: 9092
        servlet:
          context-path: /test
    
  • 启动模块的启动类,在浏览器中调用我们的接口 http://localhost:9092/test/hello ,可以在控制台中查看到具体的日志信息
      package com.tenic.springboot;
      import com.tenic.springboot.annotion.TenicLog;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.ResponseBody;
      import org.springframework.web.bind.annotation.RestController;
      @SpringBootApplication
      //@RestController
      public class SpringBootInterceptorApplication {
          public static void main(String[] args) {
              SpringApplication.run(SpringBootInterceptorApplication.class);
          }
          /**
           * 供测试使用
           */
      //    @GetMapping("/hello")
      //    @TenicLog(desc = "测试接口类")
      //    public String hello() {
      //        return "hello world!";
      //    }
      }
    
    vzskciymoxc5229.png
test-spring-boot-starter 创建
  • 我们这里只是验证上边2个starter,创建一个父工程的子模块,验证模块的目录结构比较简单,如下图所示
    4ey43yixyly5230.png
  • 我们依赖了父工程,验证上边2个模块,所以也要添加上边的模块到maven中,具体的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>demo-spring-boot-starter</artifactId>
              <groupId>com.demo</groupId>
              <version>0.0.1-RELEASE</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
          <artifactId>test-spring-boot-starter</artifactId>
          <dependencies>
              <dependency>
                  <groupId>com.demo</groupId>
                  <artifactId>properties-spring-boot-starter</artifactId>
                  <version>0.0.1-RELEASE</version>
              </dependency>
              <dependency>
                  <groupId>com.demo</groupId>
                  <artifactId>interceptor-spring-boot-starter</artifactId>
                  <version>0.0.1-RELEASE</version>
              </dependency>
          </dependencies>
      </project>
    
  • 在resource目录下创建一个application.yml的文件,配置上我们需要的配置信息
    server:
      port: 9090
      servlet:
        context-path: /tsla
    tenic:
      username: zzz
      password: abc
      driver: com.cnblog.tenic
      url: https://gitee.com/tenic/
    
  • 创建一个启动类和一个controller类,创建好之后,启动一下,访问http://localhost:9090/tsla/test, 看以在日志上看到我们的接口调用信息
      package com.tenic.springboot.controller;
      import com.tenic.springboot.annotion.TenicLog;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RestController;
      @RestController
      public class TestController {
          @GetMapping("/test")
          @TenicLog(desc = "测试接口类")
          public String hello(){
              return "hello world!";
          }
      }
    
    启动类
      package com.tenic.springboot;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      @SpringBootApplication
      public class SpringBootTestApplicaiton {
          public static void main(String[] args) {
              SpringApplication.run(SpringBootTestApplicaiton.class);
          }
      }
    
    c4mhrys1zbm5231.png
Link to comment
Share on other sites