天天看点

京东一面:谈谈你对SpringBoot Starter的理解?

作者:尚硅谷教育

我们使用SpringBoot,基本上都是沉醉在它Starter的方便之中。Starter为我们带来了众多的自动化配置,有了这些自动化配置,我们可以不费吹灰之力就能搭建一个生产级开发环境,有的小伙伴会觉得这个Starter 好神奇呀!其实Starter也都是基于Spring + SpringMVC中的基础知识点实现的,今天小编就通过自定义一个Starter来带大家了解Starter,慢慢揭开Starter的神秘面纱!

其实Starter的核心就是条件注解@Conditional。当classpath下存在某一个Class时,某个配置才会生效,大伙可能也发现了源码解读时总是会出现条件注解,其实这就是Starter配置的核心之一。

1.1Starter定义

所谓的Starter,其实就是一个普通的Maven项目,因此我们自定义Starter,需要首先创建一个普通的Maven项目,然后引入对应的依赖版本,这里我们使用的springboot版本是2.2.1.RELEASE。

# 引入依赖

<?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.2.1.RELEASE</version>

<relativePath/>

</parent>

<groupId>com.swk</groupId>

<artifactId>MyStarter</artifactId>

<version>0.0.1-SNAPSHOT</version>

<name>MyStarter</name>

<description>MyStarter</description>

<properties>

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

</properties>

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

</dependencies>

<build>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

</plugin>

</plugins>

</build>

</project>

依赖引入完成后,我们首先创建一个HelloProperties类,用来接收application.properties中注入的值。

@ConfigurationProperties(prefix = "hello")

public class HelloProperties {

private static final String DEFAULT_NAME = "隔壁老王";

private static final String DEFAULT_MSG = "隔壁小王";

private String name = DEFAULT_NAME;

private String msg = DEFAULT_MSG;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getMsg() {

return msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

}

这个配置类很好理解,将application.properties中配置的属性值直接注入到这个实例中。

@ConfigurationProperties类型安全的属性注入,即将application.properties文件中前缀为hello的属性注入到这个类对应的属性,最后使用的时候,application.properties中的配置文件,大概如下:

hello.name=zhangsan

hello.msg=java

配置完成HelloProperties后,接下来我们来定义一个HelloService,然后定义一个简单的say方法,HelloService 的定义如下:

public class HelloService {

private String msg;

private String name;

public String sayHello() {

return name + " say " + msg + " !";

}

public String getMsg() {

return msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}

接下来是重轴戏 - 定义自动配置类

@Configuration

@EnableConfigurationProperties(HelloProperties.class)

@ConditionalOnClass(HelloService.class)

public class HelloServiceAutoConfiguration {

@Autowired

private HelloProperties helloProperties;

@Bean

public HelloService helloService() {

HelloService helloService = new HelloService();

helloService.setName(helloProperties.getName());

helloService.setMsg(helloProperties.getMsg());

return helloService;

}

}

注解说明

@Configuration 注解表明这是一个配置类。

@EnableConfigurationProperties 注 解 是 使 我 们 之 前 配 置 的 @ConfigurationProperties注解生效,让配置的属性成功进入到Bean中。@ConditionalOnClass 表示当项目当前classpath下存在HelloService 时,后面的配置才生效。

自动配置类中首先注入HelloProperties,这个实例中含有我们在application.properties中配置的相关数据。

创建一个HelloService实例对象,并将HelloProperties中的值注入进去。

到这一步,我们的自动配置类就算是完成了。接下来我们还需要一个spring.factories文件。那么这个文件是干嘛的呢?大家知道我们的SpringBoot项目的启动类都有一个@SpringBootApplication注解,这个注解是一个复合注解,定义如下:

@SpringBootConfiguration

@EnableAutoConfiguration

@ComponentScan(excludeFilters = {

@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),

@Filter(type = FilterType.CUSTOM,classes = AutoConfigurationExcludeFilter.class) })

public @interface SpringBootApplication { }

我们可以看到@SpringBootApplication这是一个组合注解,其中的一个组合项就是@EnableAutoConfiguration,这个注解是干嘛的呢?

@EnableAutoConfiguration表示启用Spring应用程序上下文的自动配置,该注解会自动导入一个名为AutoConfigurationImportSelector的类,而这个类会去读取一个spring.factories的文件, spring.factories 中则定义需要加载的自动化配置类。

我们打开任意一个框架的Starter,都能看到它有一个spring.factories文件,例如 MyBatis的Starter如下:

京东一面:谈谈你对SpringBoot Starter的理解?

那么我们自定义的Starter也需要这样一个文件,我们首先在Maven项目的resources目录下创建一个名为META-INF的文件夹,然后在文件夹中创建一个名为spring.factories的文件,文件内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.swk.mystarter.config.HelloServiceAutoConfiguration

在这里指定我们的自动化配置类的路径即可,如此之后我们的自动化配置类就算完成了。

1.2使用自定义Starter

我们将这个自动化配置类安装到本地仓库,然后在其它项目中使用。安装到本地方式是在IntelliJ IDEA中,点击右边的Maven Project,然后选择 Lifecycle 中的 install,双击即可。

京东一面:谈谈你对SpringBoot Starter的理解?

创建SpringBoot工程,在其pom.xml引入自定义Starter工程依赖。

京东一面:谈谈你对SpringBoot Starter的理解?

<dependency>

<groupId>com.swk</groupId>

<artifactId>MyStarter</artifactId>

<version>0.0.1-SNAPSHOT</version>

</dependency>

引入了自定义的Starter后,我们项目中就有了一个默认的 HelloService 实例可以使用,这里我们直接在单元测试类中注入该实例完成测试。

单元测试

@RunWith(SpringRunner.class)

@SpringBootTest

public class UsemystarterApplicationTests {

@Autowired

HelloService helloService;

@Test

public void contextLoads() {

System.out.println(helloService.sayHello());

}

}

京东一面:谈谈你对SpringBoot Starter的理解?

总结

通过上述自定义Starter,相信加深了大家对Starter的理解。我们也可以看到SpringBoot所提供的这种方式主要是基于自动配置来完成的,这种方式在很大程度上减弱了原先Spring框架的配置,体现了SpringBoot框架“约定大于配置”的思想,让我们开发人员更加专注于业务实现。