SpringBoot自定义Starter(二十四)下

简介: 三. 自定义Starter 深入理解三.一 pom.xml 中添加依赖三.二 定义一个接口和两个实现类三.三 定义实现类起作用的条件三.四 让条件被管控三.五 测试三.六 Profile 多环境配置

三. 自定义Starter 深入理解

自定义的Starter 能够起作用,条件注解起了很大的作用.

演示一下条件注解的使用.

仍然使用 刚才的自定义 Starter

三.一 pom.xml 中添加依赖

   <dependencies>
        <!--添加自动配置的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>
        <!--添加配置文件引用的依赖信息-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <version>2.2.2.RELEASE</version>
            <optional>true</optional>
        </dependency>
        <!--添加 spring-context依赖, 对应的 2.2.2 版本-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.2.RELEASE</version>
        </dependency>
    </dependencies>

三.二 定义一个接口和两个实现类

定义 Animal 接口

package top.yueshushu.condition;
/**
 * @ClassName:Animal
 * @Description 定义一个动物的接口
 * @Author zk_yjl
 * @Date 2021/10/25 20:48
 * @Version 1.0
 * @Since 1.0
 **/
public interface Animal {
    /**
     * 定义一个声音的接口
     * @date 2021/10/25 20:49
     * @author zk_yjl
     * @param
     * @return void
     */
    public void voice();
}

有两个实现类, 一个是 Cat 一个是 Dog

Cat.java

package top.yueshushu.condition;
/**
 * @ClassName:Cat
 * @Description TODO
 * @Author zk_yjl
 * @Date 2021/10/25 20:50
 * @Version 1.0
 * @Since 1.0
 **/
public class Cat implements Animal {
    @Override
    public void voice() {
        System.out.println(">>>喵喵喵");
    }
}

Dog.java

package top.yueshushu.condition;
/**
 * @ClassName:Dog
 * @Description 狗的实现类
 * @Author zk_yjl
 * @Date 2021/10/25 20:49
 * @Version 1.0
 * @Since 1.0
 **/
public class Dog implements Animal {
    @Override
    public void voice() {
        System.out.println(">>>>汪汪汪");
    }
}

三.三 定义实现类起作用的条件

Animal 接口有两个实现类 Cat, Dog 在使用中,要使用哪一个呢?

总不能

@Resource("cat")
private Animal animal
@Resource("dog")
private Animal animal

这样肯定是不行的。

可以定义条件, 当Cat 的条件满足时,就用 Cat 的实现类, 当 Dog 的条件满足时,就用 Dog 的实现类

三.三.一 Cat 实现条件 CatCondition

package top.yueshushu.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
 * @ClassName:CatCondition
 * @Description TODO
 * @Author zk_yjl
 * @Date 2021/10/25 20:53
 * @Version 1.0
 * @Since 1.0
 **/
// 实现 Condition 接口
public class CatCondition implements Condition {
   @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String animal = context.getEnvironment().getProperty("animal");
        //为空属性,不创建
        if(StringUtils.isEmpty(animal)){
            return false;
        }
        return "Cat".equalsIgnoreCase(animal);
    }
}

三.三.二 Dog 实现条件 DogCondition

package top.yueshushu.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.StringUtils;
/**
 * @ClassName:DogCondition
 * @Description TODO
 * @Author zk_yjl
 * @Date 2021/10/25 20:51
 * @Version 1.0
 * @Since 1.0
 **/
public class DogCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //没有获取到这个属性时,走 Dog 
        String animal = context.getEnvironment().getProperty("animal");
        if(StringUtils.isEmpty(animal)){
            return true;
        }
        return "Dog".equalsIgnoreCase(animal);
    }
}

三.四 让条件被管控

现在有 Cat 的条件,也有 Dog 的条件。


但这两个条件,只是实现了 Condition 接口, 并没有添加形如 @Component @Configuration 等类似的注解

说明,这两个条件,还没有办法被SpringBoot 管控到.

JavaAnimalConfig 管控条件

package top.yueshushu.condition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
/**
 * @ClassName:JavaAnimalConfig
 * @Description TODO
 * @Author zk_yjl
 * @Date 2021/10/25 20:54
 * @Version 1.0
 * @Since 1.0
 **/
@Configuration
public class JavaAnimalConfig {
    /**
    条件符合时,创建
     */
    @Bean("animal")
    @Conditional(DogCondition.class)
    Animal dog(){
        return new Dog();
    }
    /**
     条件符合时,创建
     */
    @Bean("animal")
    @Conditional(CatCondition.class)
    Animal cat(){
        return new Cat();
    }
}

两者创建的,bean 都是 animal

三.五 测试

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        //ctx.getEnvironment().getSystemProperties().put("animal", "Cat");
       // ctx.getEnvironment().getSystemProperties().put("animal", "Dog");
        //  ctx.getEnvironment().getSystemProperties().put("animal", "YJL");
        ctx.register(JavaAnimalConfig.class);
        ctx.refresh();
        Animal animal = (Animal) ctx.getBean("animal");
        animal.voice();
    }
}

设置环境变量值的信息, 都去掉, 会生成默认的 Dog

当使用 Cat 时, 会打印 Cat 的实现类

当使用 Dog 时,会打印 Dog 的实现类

当使用 YJL 时, 因为都不符合,所以创建不了相应的 Bean

1.png也可以将这个自定义的Starter clean install 安装后, StarterApply 引用

@RunWith(SpringRunner.class)
@SpringBootTest
public class StarterTest {
    @Autowired
    private UserPropertiesService userPropertiesService;
    @Test
    public void starterPrintlnTest(){
        String message = userPropertiesService.println();
        System.out.println("Apply项目输出信息:"+message);
    }
   // 运行测试一下 
    @Test
    public void animalJavaTes(){
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.getEnvironment().getSystemProperties().put("animal", "Cat");
        ctx.register(JavaAnimalConfig.class);
        ctx.refresh();
        Animal animal = (Animal) ctx.getBean("animal");
        animal.voice();
    }
}

发现,也是相同的测试结果.

三.六 Profile 多环境配置

在多环境配置时,我们使用到了 Profile

在 JavaAnimalConfig 里面,

public class JavaAnimalConfig {
    /**
    条件符合时,创建
     */
    @Bean("animal")
    @Conditional(DogCondition.class)
    Animal dog(){
        return new Dog();
    }
    /**
     条件符合时,创建
     */
    @Bean("animal")
    @Conditional(CatCondition.class)
    Animal cat(){
        return new Cat();
    }
}

我们定义了 DogCondition, 能不能将这个换成 Profile 呢? 这样就不用根据环境变量的值来确定实例化哪一个实现了,而是根据环境配置来实现化具体的实现.

@Configuration
public class JavaAnimalConfig {
    /**
    条件符合时,创建
     */
    @Bean("animal")
  //  @Conditional(DogCondition.class)  不使用
    @Profile("Dog") //触发条件
    Animal dog(){
        return new Dog();
    }
    /**
     条件符合时,创建
     */
    @Bean("animal")
    //@Conditional(CatCondition.class)
    @Profile("Cat") //触发条件
    Animal cat(){
        return new Cat();
    }
}

进行测试

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        //ctx.getEnvironment().getSystemProperties().put("animal", "Cat");
       // ctx.getEnvironment().getSystemProperties().put("animal", "Dog");
       // ctx.getEnvironment().getSystemProperties().put("animal", "YJL");
       // ctx.getEnvironment().setActiveProfiles("Dog");
        //ctx.getEnvironment().setActiveProfiles("Cat");
       // ctx.getEnvironment().setActiveProfiles("YJL");
        ctx.register(JavaAnimalConfig.class);
        ctx.refresh();
        Animal animal = (Animal) ctx.getBean("animal");
        animal.voice();
    }
}

当启用 Dog 时, 实现的是 Dog

当启用的是 Cat 时,实现的是 Cat 实现

当启用的是 YJL 时,会报异常信息。与上面的测试结果一致.

也同样可以在 StarterTest 类中进行测试,

 @Test
    public void animalJavaTes(){
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        //ctx.getEnvironment().getSystemProperties().put("animal", "Cat");
        // ctx.getEnvironment().getSystemProperties().put("animal", "Dog");
        // ctx.getEnvironment().getSystemProperties().put("animal", "YJL");
         ctx.getEnvironment().setActiveProfiles("Dog");
        //ctx.getEnvironment().setActiveProfiles("Cat");
        // ctx.getEnvironment().setActiveProfiles("YJL");
        ctx.register(JavaAnimalConfig.class);
        ctx.refresh();
        Animal animal = (Animal) ctx.getBean("animal");
        animal.voice();
    }

测试结果,也是一样的。

但如果将 setActiveProfiles 都去掉,在 application.yml 中进行设置

2.png

是不可以的。 还是会报错误

3.png


相关文章
|
7月前
32SpringBoot自定义Starter
32SpringBoot自定义Starter
39 0
32SpringBoot自定义Starter
|
4天前
|
设计模式 Java 机器人
SpringBoot3自动配置流程 SPI机制 核心注解 自定义starter
SpringBoot3自动配置流程 SPI机制 核心注解 自定义starter
|
12月前
|
架构师 NoSQL Java
【案例实战】SpringBoot3.x自定义封装starter实战
【案例实战】SpringBoot3.x自定义封装starter实战
【案例实战】SpringBoot3.x自定义封装starter实战
|
4天前
|
Java Spring 容器
SpringBoot2 | SpringBoot自定义AutoConfiguration | SpringBoot自定义starter(五)
SpringBoot2 | SpringBoot自定义AutoConfiguration | SpringBoot自定义starter(五)
23 0
|
4天前
|
Java Maven Spring
Spring Boot - 手把手教小师妹自定义Spring Boot Starter
Spring Boot - 手把手教小师妹自定义Spring Boot Starter
63 0
|
4天前
|
Java 数据库连接 Maven
SpringBoot【付诸实践 01】SpringBoot自定义starter保姆级教程(说明+源码+配置+测试)
SpringBoot【付诸实践 01】SpringBoot自定义starter保姆级教程(说明+源码+配置+测试)
39 1
|
4天前
|
运维 Java Maven
SpringBoot SPI 机制和实现自定义 starter
SpringBoot SPI 机制和实现自定义 starter
52 0
|
9月前
|
Java Maven Spring
Springboot自定义Starter启动器
Springboot自定义Starter启动器.md
134 0
Springboot自定义Starter启动器
|
9月前
|
Java Maven
springboot自定义starter启动器
springboot自定义starter启动器
58 0
|
10月前
|
NoSQL Java Redis
SpringBoot入门到精通-SpringBoot自定义starter(六)
SpringBoot入门到精通-SpringBoot自定义starter