在作SpringBoot开发时,各类starter (场景启动器) 必不可少,它们就像可插拔式的插件,只要在pom文件中引用 springboot 提供的场景启动器, 再进行少许的配置就能够使用相应的功能,但SpringBoot并不能囊括咱们的全部使用场景,这时候就须要咱们自定义starter来实现定制化功能。java
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>
建立类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 + '\'' + '}'; } }
接口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)); } }
@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()); } }
在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
新建一个SpringBoot项目,将Starter工程打包并引入测试
以管理员身份运行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