美文网首页IT必备技能
Spring boot starter原理,手撸一个starte

Spring boot starter原理,手撸一个starte

作者: 三不猴子 | 来源:发表于2020-11-19 00:23 被阅读0次
    1. 什么是starter?

      starter是SpringBoot中的一个新发明,它有效的降低了项目开发过程的复杂程度,对于简化开发操作有着非常好的效果。提供一个开箱即用的组件。

    2. 手写一个starter

      假设我们有个需求,我们需要序列化一个对象,当工程中存在FastJson的com.alibaba.fastjson.JSON类时使用FastJson序列化,如果不存在就则进行简单的toString操作。

      我们首先定义一个接口有一个格式化方法

      public interface FormatProcessor {
          //定义一个序列化的方法
          <T> String format(T obj);
      }
      

      然后这个接口有两个实现类,分别做不同序列化操作。

      import com.alibaba.fastjson.JSON;
      
      public class JsonFormatProcessor implements FormatProcessor{
          @Override
          public <T> String format(T obj) {
              return "JsonFormatProcessor:"+ JSON.toJSONString(obj);
          }
      }
      
      import java.util.Objects;
      
      public class StringFormatProcessor implements FormatProcessor{
      
      
          @Override
          public <T> String format(T obj) {
              return "StringFormatProcessor:"+Objects.toString(obj);
          }
      }
      

      定义一个Configuration类。

      @Configuration
      public class FormatAutoConfiguration {
          @ConditionalOnMissingClass("com.alibaba.fastjson.JSON") // 如果不存在JSON类就加载
          @Bean
          @Primary //  如果有两个实现则优先加载这个
          public FormatProcessor stringFormat() {
              return new StringFormatProcessor();
          }
      
          @ConditionalOnClass(name = "com.alibaba.fastjson.JSON") // 如果存在JSON类
          @Bean
          public FormatProcessor jsonFormat() {
              return new JsonFormatProcessor();
          }
      }
      

      定义一个自动配置类。

      @Import(FormatAutoConfiguration.class)
      @Configuration
      public class HelloAutoConfiguration {
      
          @Bean
          public HelloFormatTemplate helloFormatTemplate( FormatProcessor formatProcessor) {
              return new HelloFormatTemplate(formatProcessor);
          }
      }
      

      template类

      public class HelloFormatTemplate {
      
          private FormatProcessor formatProcessor;
      
          public HelloFormatTemplate(FormatProcessor formatProcessor) {
              this.formatProcessor = formatProcessor;
          }
      
          public <T> String doFormat(T obj){
              StringBuilder stringBuilder=new StringBuilder();
              stringBuilder.append("begin:Execute format").append("<br/>");
              stringBuilder.append("Obj format result:").append(formatProcessor.format(obj)).append("<br/>");
              return stringBuilder.toString();
          }
      }
      

      使用spring boot的SPI机制把 HelloAutoConfiguration自动装配进spring容器。在spring.factories文件中定义

      org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
        com.yhx.starter.autoconfiguration.HelloAutoConfiguration
      

      这样我们就写出了一个starter,实现了一个类似以RedisTemplate的HelloFormatTemplate的工具。那如果我们要使用外部化的配置也就要读取到application.yml文件的配置该怎么写呢?

      首先我们写一个Properties类,并加上@ConfigurationProperties注解。

      @ConfigurationProperties(prefix = HelloProperties.HELLO_FORMAT_PREFIX)
      public class HelloProperties {
          public static final String HELLO_FORMAT_PREFIX = "yhx.hello.format";
          private Map<String, Object> info;
          public Map<String, Object> getInfo() {
              return info;
          }
          public void setInfo(Map<String, Object> info) {
              this.info = info;
          }
      }
      

      然后在HelloAutoConfiguration的自动装配的类中加上@EnableConfigurationProperties(HelloProperties.class),此时HelloAutoConfiguration类为

      @Import(FormatAutoConfiguration.class)
      @EnableConfigurationProperties(HelloProperties.class)
      @Configuration
      public class HelloAutoConfiguration {
      
          @Bean
        // HelloProperties这时候的已经在spring容器中了,会自动去找查的
          public HelloFormatTemplate helloFormatTemplate(HelloProperties helloProperties, FormatProcessor formatProcessor) {  
              return new HelloFormatTemplate(helloProperties, formatProcessor);
          }
      }
      

      这时候我们的Template可以改写为如下的

      public class HelloFormatTemplate {
      
          private FormatProcessor formatProcessor;
      
          private HelloProperties helloProperties;
      
          public HelloFormatTemplate(HelloProperties helloProperties,FormatProcessor formatProcessor) {
              this.helloProperties=helloProperties;
              this.formatProcessor = formatProcessor;
          }
      
          public <T> String doFormat(T obj){
              StringBuilder stringBuilder=new StringBuilder();
              stringBuilder.append("begin:Execute format").append("<br/>");
             stringBuilder.append("HelloProperties:").append(formatProcessor.format(helloProperties.getInfo())).append("<br/>");
              stringBuilder.append("Obj format result:").append(formatProcessor.format(obj)).append("<br/>");
              return stringBuilder.toString();
      
          }
      }
      

      我们在使用这个这个starter的工程中在application.yml或者是application.properties中配置,就可以配置进这个序列化的bean中

      yhx.hello.format.info.country=CN
      yhx.hello.format.info.provice=HuNan
      yhx.hello.format.info.city=shanghai
      yhx.hello.format.info.org=xingren
      
    3. 常见的starter之logger

      我们在项目中加入logging starter的依赖

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-logging</artifactId>
          <version>2.3.4.RELEASE</version>
      </dependency>
      

      然后看一下spring-boot-starter-logging的jar包,发现里面并没有什么,这是为什么呢?

      spring-boot-starter-logging-2.3.4.RELEASE.jar
       META-INF
           LICENSE.txt
           MANIFEST.MF
           NOTICE.txt
      

      然后我们点进pom文件中的spring-boot-starter-logging看看

      <?xml version="1.0" encoding="UTF-8"?>
      <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <!-- This module was also published with a richer model, Gradle metadata,  -->
        <!-- which should be used instead. Do not delete the following line which  -->
        <!-- is to indicate to Gradle or any Gradle module metadata file consumer  -->
        <!-- that they should prefer consuming it instead. -->
        <!-- do_not_remove: published-with-gradle-metadata -->
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-logging</artifactId>
        <version>2.3.4.RELEASE</version>
        <name>spring-boot-starter-logging</name>
        <description>Starter for logging using Logback. Default logging starter</description>
        <url>https://spring.io/projects/spring-boot</url>
        <organization>
          <name>Pivotal Software, Inc.</name>
          <url>https://spring.io</url>
        </organization>
        <licenses>
          <license>
            <name>Apache License, Version 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0</url>
          </license>
        </licenses>
        <developers>
          <developer>
            <name>Pivotal</name>
            <email>info@pivotal.io</email>
            <organization>Pivotal Software, Inc.</organization>
            <organizationUrl>https://www.spring.io</organizationUrl>
          </developer>
        </developers>
        <scm>
          <connection>scm:git:git://github.com/spring-projects/spring-boot.git</connection>
          <developerConnection>scm:git:ssh://git@github.com/spring-projects/spring-boot.git</developerConnection>
          <url>https://github.com/spring-projects/spring-boot</url>
        </scm>
        <issueManagement>
          <system>GitHub</system>
          <url>https://github.com/spring-projects/spring-boot/issues</url>
        </issueManagement>
        <dependencies>
          <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
            <scope>compile</scope>
          </dependency>
          <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-to-slf4j</artifactId>
            <version>2.13.3</version>
            <scope>compile</scope>
          </dependency>
          <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jul-to-slf4j</artifactId>
            <version>1.7.30</version>
            <scope>compile</scope>
          </dependency>
        </dependencies>
      </project>
      
      

      里面就是一堆依赖,为什么空的也能实现自动装配呢?因为spring boot官方提供了装配,如果相关的类或者一类存在的话,所以logging的starter只需要添加一些依赖就可以。

    相关文章

      网友评论

        本文标题:Spring boot starter原理,手撸一个starte

        本文链接:https://www.haomeiwen.com/subject/eqtkiktx.html