SpringBoot自定義Starter

背景

在作SpringBoot開發時,各類starter (場景啓動器) 必不可少,它們就像可插拔式的插件,只要在pom文件中引用 springboot 提供的場景啓動器, 再進行少許的配置就能夠使用相應的功能,但SpringBoot並不能囊括咱們的全部使用場景,這時候就須要咱們自定義starter來實現定製化功能。java

Spring Boot Starter工做原理

  • 1.SpringBoot在啓動的時候會掃描項目所依賴的JAR包,尋找包含spring.factories文件的JAR包
  • 2.讀取spring.factories文件獲取配置的自動配置類AutoConfiguration
  • 3.將自動配置類下知足條件(@ConditionalOnXxx)的@Bean放入到Spring容器中(Spring Context)

自定義starter

1.建立一個maven工程

pom文件spring

<?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">
    <modelVersion>4.0.0</modelVersion>

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

    <groupId>com.matins.starter</groupId>
    <artifactId>hello-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>hello-spring-boot-starter</name>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--啓動器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

2.Proprerty類

建立類PersonPropertiesapache

@ConfigurationProperties註解的做用是告訴SpringBoot將本類中的全部屬性和配置文件中相關的配置進行綁定,prefix 指定配置文件裏的前綴,配置了這個註解後會根據配置文件的全部屬性進行一一映射springboot

package com.matins.starter.property;


import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @Description:
 * @author: wei.wang
 * @since: 2019/12/18 23:46
 * @history: 1.2019/12/18 created by wei.wang
 */
@ConfigurationProperties(prefix = "spring.person")
public class PersonProperties {
    // 姓名
    private String name;
    // 年齡
    private int age;
    // 性別
    private String sex = "M";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "PersonProperties{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}

3.Service類

接口PersonServiceapp

package com.matins.starter.service;

/**
 * @Description:
 * @author: wei.wang
 * @since: 2020/6/24 16:37
 * @history: 1.2020/6/24 created by wei.wang
 */
public interface PersonService {

    void hello();
}

類PersonServiceImplmaven

package com.matins.starter.service.impl;

import com.matins.starter.service.PersonService;

/**
 * @Description:
 * @author: wei.wang
 * @since: 2020/6/24 16:38
 * @history: 1.2020/6/24 created by wei.wang
 */
public class PersonServiceImpl implements PersonService {

    // 姓名
    private String name;
    // 年齡
    private int age;
    // 性別
    private String sex = "M";

    public PersonServiceImpl(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    @Override
    public void hello() {
        System.out.println(String.format("Hello from the default starter , name %s, age %s, sec %s", name, age, sex));
    }
}

4.自動配置類

@Configuration //指定這個類是一個配置類
@ConditionalOnXXX //指定條件成立的狀況下自動配置類生效
@AutoConfigureOrder //指定自動配置類的順序
@Bean //向容器中添加組件
@ConfigurationProperties //結合相關xxxProperties來綁定相關的配置
@EnableConfigurationProperties //讓xxxProperties生效加入到容器中
@ConditionalOnClass:當類路徑classpath下有指定的類的狀況下進行自動配置
@ConditionalOnMissingBean:當容器(Spring Context)中沒有指定Bean的狀況下進行自動配置
@ConditionalOnProperty(prefix = 「example.service」,name = "auth", value = 「enabled」, matchIfMissing = true),當配置文件中example.service.auth.enabled=true時進行自動配置,若是沒有設置此值就默認使用matchIfMissing對應的值
@ConditionalOnMissingBean,當Spring Context中不存在該Bean時。
@ConditionalOnBean:當容器(Spring Context)中有指定的Bean的條件下
@ConditionalOnMissingClass:當類路徑下沒有指定的類的條件下
@ConditionalOnExpression:基於SpEL表達式做爲判斷條件
@ConditionalOnJava:基於JVM版本做爲判斷條件
@ConditionalOnJndi:在JNDI存在的條件下查找指定的位置
@ConditionalOnNotWebApplication:當前項目不是Web項目的條件下
@ConditionalOnWebApplication:當前項目是Web項目的條件下
@ConditionalOnResource:類路徑下是否有指定的資源
@ConditionalOnSingleCandidate:當指定的Bean在容器中只有一個,或者在有多個Bean的狀況下,用來指定首選的Bean

自動配置類PersonServiceAutoConfigurationide

package com.matins.starter.configuration;

import com.matins.starter.property.PersonProperties;
import com.matins.starter.service.PersonService;
import com.matins.starter.service.impl.PersonServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


/**
 * @Description:
 * @author: wei.wang
 * @since: 2020/6/24 16:38
 * @history: 1.2020/6/24 created by wei.wang
 */
@Configuration
@EnableConfigurationProperties(PersonProperties.class)
@ConditionalOnClass(PersonService.class)
public class PersonServiceAutoConfiguration {

    @Autowired
    private PersonProperties properties;

    @Bean(name = "person")
    public PersonService helloService() {
        return new PersonServiceImpl(properties.getName(), properties.getAge(), properties.getSex());
    }
}

5.配置文件

在resources/META-INF/下建立文件spring.factories,SpringBoot在啓動的時候會掃描項目所依賴的JAR包,尋找包含spring.factories文件的JAR包,讀取spring.factories文件獲取配置的自動配置類AutoConfiguration,而後將自動配置類下知足條件(@ConditionalOnXxx)的@Bean放入到Spring容器中(Spring Context),這樣使用者就能夠直接用來注入,由於該類已經在容器中了spring-boot

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.matins.starter.configuration.PersonServiceAutoConfiguration

6.測試

新建一個SpringBoot項目,將Starter工程打包並引入測試

添加本地jar包到Maven

以管理員身份運行CMDthis

mvn install:install-file -Dfile="F:\GitCode\zero\hello-spring-boot-starter\target\hello-spring-boot-starter-1.0-SNAPSHOT.jar" -DgroupId=com.matins.starter -DartifactId=hello-spring-boot-starter -Dversion=0.0.1-SNAPSHOT -Dpackaging=jar

而後在Maven中引用

<dependency>
            <groupId>com.matins.starter</groupId>
            <artifactId>hello-spring-boot-starter</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

配置文件

在application.properties中添加,PersonProperties中使用了 @ConfigurationProperties(prefix = "spring.person"),prefix 指定配置文件裏的前綴,會根據配置的信息將屬性一一映射

spring.person.age=23
spring.person.name=ss
spring.person.sex=F

測試方法

能夠直接@Autowired自動注入,或者使用getBean的方法獲取bean

package com.zero.auth.controller;


import com.matins.starter.property.PersonProperties;
import com.matins.starter.service.PersonService;
import com.zero.auth.config.SpringUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @Description:
 * @author: wei.wang
 * @since: 2019/12/19 0:34
 * @history: 1.2019/12/19 created by wei.wang
 * <p>
 * Spring Boot在啓動時掃描項目所依賴的JAR包,尋找包含spring.factories文件的JAR包,
 * 而後讀取spring.factories文件獲取配置的自動配置類AutoConfiguration,
 * 而後將自動配置類下知足條件(@ConditionalOnXxx)的@Bean放入到Spring容器中(Spring Context)
 * 這樣使用者就能夠直接用來注入,由於該類已經在容器中了
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestControllerTest {

    @Autowired
    PersonService personService1;

    @Autowired
    private PersonProperties properties;


    @Test
    public void auth() {
        PersonService personService = (PersonService) SpringUtil.getBean("person");
        personService.hello();
        personService1.hello();
    }
}

SpringUtil

package com.zero.auth.config;


import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * @Description:
 * @author: wei.wang
 * @since: 2020/6/25 16:56
 * @history: 1.2020/6/25 created by wei.wang
 */
@Component
public class SpringUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContextParam) throws BeansException {
        applicationContext = applicationContextParam;
    }

    public static Object getObject(String id) {
        Object object = null;
        object = applicationContext.getBean(id);
        return object;
    }

    public static <T> T getObject(Class<T> tClass) {
        return applicationContext.getBean(tClass);
    }

    public static Object getBean(String tClass) {
        return applicationContext.getBean(tClass);
    }

    public <T> T getBean(Class<T> tClass) {
        return applicationContext.getBean(tClass);
    }
}

測試結果

Hello from the default starter , name ss, age 23, sec F
Hello from the default starter , name ss, age 23, sec F
相關文章
相關標籤/搜索