序
我们都知道可以使用SpringBoot快速的开发基于Spring框架的项目。由于围绕SpringBoot存在很多开箱即用的Starter依赖,使得我们在开发业务代码时能够非常方便的、不需要过多关注框架的配置,而只需要关注业务即可。
那么什么是starter呢?
例如我想要在SpringBoot项目中集成Redis,那么我只需要加入spring-data-redis-starter的依赖,并简单配置一下连接信息以及Jedis连接池配置就可以。这为我们省去了之前很多的配置操作。甚至有些功能的开启只需要在启动类或配置类上增加一个注解即可完成。
一个starter的原理
首先说说原理,我们知道使用一个公用的starter的时候,只需要将相应的依赖添加的Maven的配置文件当中即可,免去了自己需要引用很多依赖类,并且SpringBoot会自动进行类的自动配置。那么 SpringBoot 是如何知道要实例化哪些类,并进行自动配置的呢? 下面简单说一下。
首先,SpringBoot 在启动时会去依赖的starter包中寻找 resources/META-INF/spring.factories
文件,然后根据文件中配置的Jar包去扫描项目所依赖的Jar包,这类似于 Java 的 SPI 机制。
第二步,根据 spring.factories
配置加载AutoConfigure
类。
最后,根据 @Conditional
注解的条件,进行自动配置并将Bean注入Spring Context 上下文当中。
我们也可以使用@ImportAutoConfiguration({MyServiceAutoConfiguration.class})
指定自动配置哪些类。
定义一个start(首先一个starter是一个是一个简单的maven工程,不是一个spring boot的工程)的过程:
1.首先我们新建一个maven的项目(记住,是maven的项目,不能定义一个spring boot(如果定义成spring boot的项目,我们需要删除启动类,pom中的依赖等)的项目)
2.新建完maven项目后,我们再pom的包中导入如下两个依赖(用于加载配置文件的依赖):
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.0.0.RELEASE</version>
<optional>true</optional>
</dependency>
</dependencies>
3.建立配置文件:
a.我们看redis,搜索RedisProperties这个类,可以看到在redis-starter中,有一个定义的对象。如下:
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
private int database = 0;
private String url;
private String host = "localhost";
private String password;
private int port = 6379;
}
b.依葫芦画瓢,我们定义一个属于自己的properties类
@Data
@ConfigurationProperties(prefix = "spring.person")
public class PersonProperties {
// 姓名
private String name;
// 年龄
private int age;
// 性别
private String sex = "M";
}
4.服务类:
每一个starter都有自己的功能,如:redis的,根据配置文件连接到redis,提供出连接池等。所以每个服务只有
有一个服务核心类(可以有多个,在下面写配置文件的时候可以看到),如下,我们定义个一个属于自己的服务
核心类:
public class PersonService {
private PersonProperties properties;
public PersonService() {
}
public PersonService(PersonProperties properties) {
this.properties = properties;
}
public void sayHello(){
System.out.println("大家好,我叫: " + properties.getName() + ", 今年" + properties.getAge() + "岁"
+ ", 性别: " + properties.getSex());
}
}
5.自动配置类:
这个自动配置类就是最重要的,通过第一步引入的两个jar包提供的一个注解,既可以将服务提供出去
如:在redis中,有一个RedisAutoConfiguration。依RedisAutoConfiguration,我们可以建一个PersonServiceAutoConfiguration
这个类:
@Configuration
@EnableConfigurationProperties(PersonProperties.class)
@ConditionalOnClass(PersonService.class)
@ConditionalOnProperty(prefix = "spring.person", value = "enabled", matchIfMissing = true)
public class PersonServiceAutoConfiguration {
@Autowired
private PersonProperties properties;
@Bean
@ConditionalOnMissingBean(PersonService.class) // 当容器中没有指定Bean的情况下,自动配置PersonService类
public PersonService personService(){
PersonService personService = new PersonService(properties);
return personService;
}
}
下面是一个注释的使用方式:
@ConditionalOnClass:当类路径classpath下有指定的类的情况下进行自动配置
@ConditionalOnMissingBean:当容器(Spring Context)中没有指定Bean的情况下进行自动配置
@ConditionalOnProperty(prefix = “example.service”, value = “enabled”, matchIfMissing = true),当配置文件中example.service.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
6.设置配置文件:
创建src/main/resources/META-INF/spring.factories的配置文件,并且在配置文件中配置上刚才自定义的PersonServiceAutoConfiguration类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.mengday.helloworld.PersonServiceAutoConfiguration
注:如果有多个配置文件类,那么写法如下
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,
7.打包maven项目,clean+install
8.在一个新的spring boot项目中引入这个pom
9.配置application.properties
spring.person.name=test
spring.person.age=28
10.在新的spring boot项目中写一个test:
import com.mengday.helloworld.PersonService;
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;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MystarterApplicationTests {
@Autowired
private PersonService personService;
@Test
public void testHelloWorld() {
personService.sayHello();
}
}
终:最后一个自定义的starter就成功了。
starter的用处:
自定义starter可以用于封装一些公司内部框架的连接