网上介绍的各类的基于spring的starter基本都是最简单的hello word级别的例子,拿来真心没什么用处,最多就是让你了解到有这么一个东西,然后没有然后了,那么我们假设现在有以下的场景,假定你自己写了一个很牛叉的鉴权模块,需要给到别人使用,那我们希望别人在使用的时候,若没有实现我们的鉴权接口,则使用默认的鉴权接口,若实现了我们的鉴权接口,那就使用实现以后的鉴权接口,那这时候我们该如何去实现呢?第一种实现方式我们在新的实现上加上@Primary注解,这种方式就不是很优雅了,那我们是否有更优雅的实现方式,那么接下来我们就开始说下我们的优雅的实现方式。

 

1、编写我们的鉴权模块

1.1、创建鉴权模块的核心工程

首先我们使用idea创建一个鉴权模块名称为“spring-starter-core-demo”,以下为创建完成以后的pom.xml

<?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.3.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lazyboyl.demo</groupId>
    <artifactId>spring-starter-core-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-starter-core-demo</name>
    <description>这是一个关于starter的demo例子</description>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <!-- 此处大家一定要记得修改啊,要不到时候你自己编写的牛叉的插件安装到maven以后你会发现无法在别的工程使用 -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

工程目录如下所示:
带你玩转属于自己的spring-boot-starter系列(一)_spring starter

1.2、创建核心的鉴权接口

接着我们在工程底下创建一个auth的包,同时在该包底下创建一个鉴权接口如下所示:

package com.lazyboyl.demo.auth;

/**
 * @author linzf
 * @since 2020/9/16
 * 类描述: 实现用户的鉴权
 */
public interface UserAuth {

    /**
     * 功能描述: 实现用户的鉴权
     * @param url 响应的接口地址
     * @return 返回鉴权结果
     */
    boolean authAction(String url);

}

1.3、创建核心的鉴权接口

接着创建我们核心的鉴权接口的默认实现,代码如下所示:

package com.lazyboyl.demo.auth.impl;

import com.lazyboyl.demo.auth.UserAuth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @author linzf
 * @since 2020/9/16
 * 类描述:
 */

public class UserAuthDefault implements UserAuth {

    private Logger log = LoggerFactory.getLogger(UserAuthDefault.class);

    @Override
    public boolean authAction(String url) {
        log.info("你当前请求的是一个默认的鉴权方法");
        return true;
    }
}

1.4、创建我们的starter的配置文件

代码如下所示:

package com.lazyboyl.demo.config;

import com.lazyboyl.demo.auth.impl.UserAuthDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author linzf
 * @since 2020/9/16
 * 类描述: 配置类
 */
@Configuration
public class StarterAutoConfigure {

    private Logger log = LoggerFactory.getLogger(StarterAutoConfigure.class);

    /**
     * 功能描述: 当没有类实现UserAuth接口同时注入的时候默认注入UserAuthDefault
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(name = "userAuth")
    public UserAuthDefault userAuth() {
        log.info("-----我被初始化了-----");
        return new UserAuthDefault();
    }

}

1.5、配置我们的starter

最后在我们的resource文件夹底下创建一个META-INF文件夹,然后再这个文件夹底下创建一个spring.factories文件,该文件的内容如下所示:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.lazyboyl.demo.config.StarterAutoConfigure

到此处我们就完成了我们的核心鉴权模块的构建了,接下来我们将开始验证这个插件是否满足我们的需求。

2、验证不实现UserAuth的例子的场景

2.1、创建验证不实现UserAuth的工程

首先我们使用idea创建一个鉴权模块名称为“spring-starter-demo-one”,这边一定要记得引入前面我们编写好的核心工程的maven依赖,以下为创建完成以后的pom.xml

<?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.3.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lazyboyl.demo</groupId>
    <artifactId>spring-starter-demo-one</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-starter-demo-one</name>
    <description>不实现UserAuth的例子的展示</description>

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

    <dependencies>
        <!-- 上个工程编写好的核心依赖 -->
        <dependency>
            <groupId>com.lazyboyl.demo</groupId>
            <artifactId>spring-starter-core-demo</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.2、创建验证的代码

代码如下:

package com.lazyboyl.demo.one.controller;

import com.lazyboyl.demo.auth.UserAuth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author linzf
 * @since 2020/9/16
 * 类描述:
 */
@RestController
public class DemoOneController {

    @Autowired
    private UserAuth userAuth;

    @GetMapping("test")
    public String test() {
        userAuth.authAction("test");
        return "test";
    }

}

2.3、验证效果

我们直接启动当前的“spring-starter-demo-one”这个工程,这时候大家可以在控制台看到如下的信息:
带你玩转属于自己的spring-boot-starter系列(一)_spring starter_02
大家看到这边**“我被初始化了”**这段文字了,这说明我们在没有做任何配置的时候,默认采用的是我们的默认实现,我们可以直接接着响应下我们前面编写的接口,大家可以看到控制台如下的输出:
带你玩转属于自己的spring-boot-starter系列(一)_spring starter_03
到此为止我们就验证了我们的初步设想了,在我们不再次注入UserAuth的相关实现的bean的时候,默认采用的是最初默认的实现。

3、验证实现UserAuth的例子的场景

3.1、创建验证实现UserAuth的工程

首先我们使用idea创建一个鉴权模块名称为“spring-starter-demo-two”,这边一定要记得引入前面我们编写好的核心工程的maven依赖,实际上这个和前面的工程是一样的,只是为了方便测试效果才创建了这个工程,以下为创建完成以后的pom.xml

<?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.3.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lazyboyl.demo</groupId>
    <artifactId>spring-starter-demo-two</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-starter-demo-two</name>
    <description>实现UserAuth的例子展示</description>

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

    <dependencies>

        <dependency>
            <groupId>com.lazyboyl.demo</groupId>
            <artifactId>spring-starter-core-demo</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3.2、创建验证的代码

这段的代码和第一个例子的代码是一样的没有任何的区别,代码如下所示:

package com.lazyboyl.demo.two.controller;

import com.lazyboyl.demo.auth.UserAuth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author linzf
 * @since 2020/9/16
 * 类描述:
 */
@RestController
public class DemoTwoController {

    @Autowired
    private UserAuth userAuth;

    @GetMapping("test")
    public String test() {
        userAuth.authAction("test");
        return "test";
    }

}

3.3、实现新的鉴权

在此处我们实现UserAuth自己的鉴权方式,同时将这个鉴权注入到我们的spring体系中,在此处一个需要注意的地方是,我们需要设置@Component(“userAuth”)里面的“userAuth”需要和我们的核心@ConditionalOnMissingBean(name = “userAuth”)里面“userAuth”的名称要一致的,否则我们的核心包在扫描的时候则会去寻找是否有userAuth的注入,若找不到,则会再次创建默认的实现。

package com.lazyboyl.demo.two.auth;

import com.lazyboyl.demo.auth.UserAuth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * @author linzf
 * @since 2020/9/16
 * 类描述:
 */
@Component("userAuth")
public class UserAuthImpl implements UserAuth {

    private Logger log = LoggerFactory.getLogger(UserAuthImpl.class);

    @Override
    public boolean authAction(String url) {
        log.info("----我是被重新定义的鉴权的方法----");
        return false;
    }
}

3.4、验证效果

我们直接启动当前的“spring-starter-demo-two”这个工程,这时候大家可以在控制台看到如下的信息:
带你玩转属于自己的spring-boot-starter系列(一)_spring starter_04
这时候大家注意到我们启动的时候并没有去实例化我们的核心包中的默认实现了,这时候我们直接响应下我们编写的默认接口:
带你玩转属于自己的spring-boot-starter系列(一)_spring starter_05
大家看到这时候调用的就是我们的默认实现了,这样就完美的解决了我们需要的场景了。

4、总结

通过上述的描述,我们就可以联想到我们需要使用的场景了,假定你现在需要写一个很牛叉的模块给到别人使用,然后里面有某几个接口在别人使用你的模块的时候,若是不实现则直接使用默认的实现,若使用的人需要则只需要实现你的接口,然后在上面自己的代码即可,这时候你就可以考虑使用以上的场景去处理你的业务场景了。