springboot 1.5.3 源码分析(二):springboot自动化配置原理及自定义starter

来源:互联网 发布:iphone7plus无移动数据 编辑:程序博客网 时间:2024/04/25 08:41

前面的文章已经讲了springboot的实现原理,无非就是通过spring的condition条件实现的,还是比较简单的(感谢spring设计的开放性与扩展性)。
在实际工作过程中会遇到需要自定义starter的需求,那么我们接下来就自己实现一个starter。

先看一下目录结构:
这里写图片描述

  • MyConfig是自定义的配置类
  • HelloService是自定义的bean
  • HelloServiceProperties是自定义的类型安全的属性配置
  • MEYA-INF/spring.factories文件是springboot的工厂配置文件

本项目就是自定义的starter。假设我们这里需要一些配置项,使用者在使用该starter时,需要在application.properties文件中配置相关属性。这里我们使用了@ConfigurationProperties来将属性配置到一个POJO类中。这样做的好处是:可以检测数据的类型,并且可以对数据值进行校验,详情请参考我的另一篇博客:

HelloServiceProperties类内容如下:

import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;/** * Created by hzliubenlong on 2017/12/13. */@Data@Component@ConfigurationProperties(prefix = "hello")public class HelloServiceProperties {    private String a;    private String b;}

这样使用这个starter的时候,就可以配置hello.a=**来设置属性了。

HelloService是我们的bean,这里实现比较简单,获取外部的属性配置,打印一下日志。内容如下:

/** * Created by hzliubenlong on 2017/12/12. */@Slf4jpublic class HelloService {    String initVal;    public void setInitVal(String initVal) {        this.initVal = initVal;    }    public String getInitVal() {        return initVal;    }    public String hello(String name) {        log.info("initVal={}, name={}", initVal, name);        return "hello " + name;    }}

接下来是比较重要的配置类MyConfig,前面已经讲过,springboot是通过条件注解来判断是否要加载bean的,这些内容都是在我们自定义的配置类中来实现:

import com.example.myservice.HelloService;import com.example.properties.HelloServiceProperties;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configuration@EnableConfigurationProperties(HelloServiceProperties.class)public class MyConfig {    @Autowired    private HelloServiceProperties helloServiceProperties;    @ConditionalOnProperty(prefix="hello", value="enabled", matchIfMissing = true)    @ConditionalOnClass(HelloService.class)    @Bean    public HelloService initHelloService() {        HelloService helloService = new HelloService();        helloService.setInitVal(helloServiceProperties.getA());        return helloService;    }}

@Configuration表明这是一个配置类
@EnableConfigurationProperties(HelloServiceProperties.class)表示该类使用了属性配置类HelloServiceProperties
initHelloService()方法就是实际加载初始化helloServicebean的方法了,它上面有三个注解:
1. @ConditionalOnProperty(prefix="hello", value="enabled", matchIfMissing = true): hello.enabled=true时才加载这个bean,配置没有的话,默认为true,也就是只要引入了这个依赖,不做任何配置,这个bean默认会加载。
2. @ConditionalOnClass(HelloService.class):当HelloService这个类存在时才加载bean。
3. @Bean:表明这是一个产生bean的方法,改方法生成一个HelloService的bean,交给spring容器管理。

好了,到这里,我们的代码已经写完。根据前面讲的springboot的原理我们知道,springboot是通过扫描MEYA-INF/spring.factories这个工厂配置文件来加载配置类的, 所以我们还需要创建这个文件。其内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.example.demo.MyConfig

上面的\是换行符,只是为了便于代码的阅读。通过这个文件,springboot就可以读取到我们自定义的配置类MyConfig。
接下来我们只需要打个jar包即可供另外一个项目使用了。下面贴一下pom.xml的内容:

<?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>    <groupId>com.example</groupId>    <artifactId>springboot-starter-hello</artifactId>    <version>0.0.1-SNAPSHOT</version>    <packaging>jar</packaging>    <name>springboot-starter-hello</name>    <description>Demo project for Spring Boot</description>    <parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>1.5.3.RELEASE</version>        <relativePath/> <!-- lookup parent from repository -->    </parent>    <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>            <optional>true</optional>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </dependency>    </dependencies>    <build>        <plugins>            <plugin>                <artifactId>maven-release-plugin</artifactId>                <version>2.4.2</version>                <dependencies>                    <dependency>                        <groupId>org.apache.maven.scm</groupId>                        <artifactId>maven-scm-provider-gitexe</artifactId>                        <version>1.8.1</version>                    </dependency>                </dependencies>            </plugin>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <version>3.3</version>                <configuration>                    <source>1.8</source>                    <target>1.8</target>                    <encoding>UTF-8</encoding>                </configuration>            </plugin>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-surefire-plugin</artifactId>                <version>2.19.1</version>                <configuration>                    <skip>false</skip>                </configuration>            </plugin>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-resources-plugin</artifactId>                <version>2.7</version>                <configuration>                    <encoding>UTF-8</encoding>                </configuration>            </plugin>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-source-plugin</artifactId>                <executions>                    <execution>                        <id>attach-sources</id>                        <goals>                            <goal>jar</goal>                        </goals>                    </execution>                </executions>            </plugin>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-jar-plugin</artifactId>                <version>2.4</version>                <configuration>                    <archive>                        <manifest>                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>                        </manifest>                    </archive>                </configuration>            </plugin>        </plugins>    </build></project>

上面定义了一个starter,下面我们将写一个新的工程,来引用我们自定义的starter。还是先看一下项目目录:
这里写图片描述
要想引用我们自定义的starter,自然是先引入依赖了:

<dependency>            <groupId>com.example</groupId>            <artifactId>springboot-starter-hello</artifactId>            <version>0.0.1-SNAPSHOT</version>        </dependency>

然后再application.properties文件中添加如下配置:

hello.enabled=truehello.a=hahaha

好了,现在就可以在项目中注入HelloService使用了。是的,就是那么简单.DemoApplication主类如下:

import com.example.demo.environment.EnvironmentService;import com.example.myservice.HelloService;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@Slf4j@SpringBootApplicationpublic class DemoApplication {    @Autowired    HelloService helloService;    @RequestMapping("/")    public String word(String name) {        return helloService.hello(name);    }    public static void main(String[] args) {        SpringApplication.run(DemoApplication.class, args);    }}

启动项目,访问URLhttp://127.0.0.1:8080/?name=hhh:
这里写图片描述
后台打印日志为initVal=hahaha, name=hhh其中hahaha就是我们没在配置文件中配置的属性值,这句日志是我们上面starter项目中com.example.myservice.HelloService#hello方法打印出来的。

end。

阅读全文
0 0