跳至主要內容

Springboot之starter

xw大约 2 分钟SpringJavaSpring Boot

0x1 starter介绍

starter是可插拔插件,springBoot自带了很多的starter,它与jar包的区别是starter能自动实现配置,极大提升了开发人员的效率。

0x2 conditional相关注解介绍

starter大量使用了conditional注解,conditional的作用是根据是否满足特定条件来决定是否创建某个特定的Bean,这是Springboot实现自动配置的关键基础能力。常见的conditional注解有:

  • @ConditioncalOnBean
  • @ConditionalOnMissBean
  • @ConditionalOnClass
  • @ConditionalOnMissingClass
  • @ConditionalOnWebApplication
  • @ConditionalOnProperty (判断特定属性是否存在)
  • @ConditionalOnNotWebApplication (判断是否为Web环境)
  • @ConditionalOnJava (判断java版本)

对于上述注解的使用在这里不过多阐述,下面实现自己的conditional注解。

首先定义注解类:

package com.example.demo.conditional;

import org.springframework.context.annotation.Conditional;

import java.lang.annotation.*;

/**
 * @Author : yangliu@tiduyun.com
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({PropertiesConditional.class})
public @interface MyConditionalOnProperties {

    String[] value() default {};
}

实现:

package com.example.demo.conditional;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;

/**
 * @Author : yangliu@tiduyun.com
 */
public class PropertiesConditional implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 获取数据
        final String[] properties = (String[])metadata
            .getAnnotationAttributes("com.example.demo.conditional.MyConditionalOnProperties").get("value");
        for (String property : properties) {
            if (StringUtils.isEmpty(context.getEnvironment().getProperty(property))) {
                return false;
            }
        }

        return true;
    }
}

测试,声明类A,使用自定义注解,此时没有xw.name属性,类A没有进行注入,使用类A会引起报错,添加变量后成功。

package com.example.demo.conditional;

import org.springframework.stereotype.Component;

/**
 * @Author : yangliu@tiduyun.com
 */
@Component
@MyConditionalOnProperties({"xw.name"})
public class A {
}

package com.example.demo;

import com.example.demo.conditional.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@SpringBootApplication
@PropertySource(value ={"classpath:a/a.properties", "classpath:b.properties"})
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Autowired
    private A a;


}

0x3 自定义starter

新建Mylog

package com.example.starter.log;

/**
 * @Author : yangliu@tiduyun.com
 */
public interface MyLog {

    void log(String value);
}

DefaultLog类

package com.example.starter.log;

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Component;

/**
 * @Author : yangliu@tiduyun.com
 */

@ConditionalOnMissingBean(value = ErrorMyLog.class)
public class DefaultMyLog implements MyLog {

    @Override
    public void log(String value) {
        System.out.println("default log method " + value);
    }
}

src/main/resources/META-INF/spring.factories启动自动加载

org.springframework.boot.autoconfigure.EnableAutoConfiguration=xxx

ErrorLog类:

package com.example.starter.log;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

/**
 * @Author : yangliu@tiduyun.com
 */
@Component
@ConditionalOnProperty(value = "error.log", havingValue = "true")
public class ErrorMyLog implements MyLog {
    @Override
    public void log(String value) {
        System.out.println("error log " + value);
    }
}

主要代码如上,当有error.log属性并且值为true时使用ErrorLog,否则使用DefaultLog。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 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.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>log-sping-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>starter</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.0-M5</spring-cloud.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</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
    </dependencyManagement>

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

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

</project>