`
阅读更多

 

编写不易,转载请注明(http://shihlei.iteye.com/blog/2407689)!

一 概述

SpringBoot 个人感觉特点:

1)众多库的集合(各种Starter),方便快速构建应用系统。

2)自动配置spring(通过AutoConfiguration机制),简化配置,也方便扩展新的Starter。

3)内嵌web容器,无需WAR部署。

 

本文自定义一个helloworld-starter 揭示starter的定义过程,及Spring AutoConfiguration 自动配置方法。

 

注:

SpringBoot AutoConfiguration机制: 

    SpringBoot启动时,扫描 classpath 所有Jar中 META-INF/spring.factories文件,读取org.springframework.boot.autoconfigure.EnableAutoConfiguration 指定的Configuration,根据Configuration上的Conditional条件自动创建bean,注入容器。

 

Spring自动配置的Starter及自动配置能力,由如下包提供。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
    <version>1.5.9.RELEASE</version>
</dependency>

 

关于Spring框架@Configuration使用,可参见博客《Spring:@Configuration 使用》

 

二 Demo 工程规划

(1)spring-boot-helloworld-starter项目—— 自定义Starter

实现 HelloWorldTemplate 自动配置,并根据classpath 中是否有FastJson包,决定格式化信息方式

 

 

(2)spring-boot-web 项目—— 调用Starter

依赖spring-boot-helloworld-starter项目HelloWorldTemplate,将格式化的信息返回客户端(信息包括application.yml中的 helloworld.author中信息,“Hello World”,调用的传入的对象信息)

 

 

三 spring-boot-helloworld-starter项目

(1)工程:

1)父 pom : 

其中:spring-boot-dependencies 提供了spring boot的依赖声明

 

<?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>x.demo.springboot.starter</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>module/spring-boot-helloworld-starter</module>
    </modules>

    <properties>
        <java.version>1.8</java.version>
        <spring.boot.version>1.5.9.RELEASE</spring.boot.version>
        <fastjson.version>1.2.28</fastjson.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- spring boot 基础依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>${fastjson.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>${java.version}</source>
                        <target>${java.version}</target>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

    

 

2)module: 

其中FastJson 使用,<optional>true</optional> ,指定客户端可以选择依赖该jar,用于实现如果classpath 中没有fastjson的jar,则不使用JSON FastJsonOutputFormater

 

<?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">
    <parent>
        <artifactId>spring-boot-starter</artifactId>
        <groupId>x.demo.springboot.starter</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <!-- @ConfigurationProperties annotation processing (metadata for IDEs) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <!-- 指定客户端可以选择依赖该jar,用于实现如果classpath 中没有fastjson的jar,则不使用JSON FastJsonOutputFormater-->
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

 

 

(2)主要服务类:HelloWorldTemplate

实现组装配置文件中的作者信息、HelloWorld、用户传入的对象信息

 

package x.demo.springboot.starter.hw;

import x.demo.springboot.starter.hw.autoconfiguration.HelloWorldProperties;
import x.demo.springboot.starter.hw.outputformater.OutputFormater;

/**
 * 配置文件中的作者信息
 * HelloWorld
 * 对象信息
 */
public class HelloWorldTemplate {

    private HelloWorldProperties helloWorldProperties;

    private OutputFormater outputFormater;

    public HelloWorldTemplate(HelloWorldProperties helloWorldProperties, OutputFormater outputFormater) {
        this.helloWorldProperties = helloWorldProperties;
        this.outputFormater = outputFormater;
    }

    /**
     * 打印作者信息
     * 打印对象信息
     *
     * @param obj 打印的对象
     */
    public <T> String generate(T obj) {
        StringBuilder message = new StringBuilder();
        message.append("author: ").append(outputFormater.format(helloWorldProperties.getAuthor())).append("\n");
        message.append("say: Hello World!").append("\n");
        message.append("object: ").append(outputFormater.format(obj)).append("\n");
        return message.toString();
    }
}

 

 

(3)HelloWorldProperties:映射application.yaml文件中的 helloworld.authors信息:

以通过@ConfigurationProperties(prefix = HelloWorldProperties.HELLOWORLD_PREFIX) 标识是属性映射类,同时指定了在主配置文件中的前缀。需要通过@EnableConfigurationProperties(HelloWorldProperties.class)开启。

 

package x.demo.springboot.starter.hw.autoconfiguration;

import java.util.Map;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * 用于springboot 从配置文件 (application.yml) 中读取 helloworld配置
 */
@ConfigurationProperties(prefix = HelloWorldProperties.HELLOWORLD_PREFIX)
public class HelloWorldProperties {

    public static final String HELLOWORLD_PREFIX = "helloworld";

    private Map<String, Object> author;

    public Map<String, Object> getAuthor() {
        return author;
    }

    public void setAuthor(Map<String, Object> author) {
        this.author = author;
    }
}

 

 

(4)OutputFormater:输出格式化:

1)接口

 

package x.demo.springboot.starter.hw.outputformater;

/**
 * 格式化工具
 */
public interface OutputFormater {

    /**
     * 格式
     * @param obj 对象
     * @return 格式字符串
     */
    <T> String format(T obj);
}

 

 

2)toString()实现

 

package x.demo.springboot.starter.hw.outputformater;

import java.util.Objects;

/**
 * 使用对象toString() 格式化
 */
public class ToStringOutputFormater implements OutputFormater {
    /**
     * 格式
     *
     * @param obj 对象
     * @return 格式字符串
     */
    public <T> String format(T obj) {
        return "ToStringOutputFormater:" +Objects.toString(obj);
    }
}

 

 

3)json 实现

 

package x.demo.springboot.starter.hw.outputformater;

import com.alibaba.fastjson.JSON;

/**
 * 使用fastjson格式化
 */
public class FastJsonOutputFormater implements OutputFormater {
    /**
     * 格式
     *
     * @param obj 对象
     * @return 格式字符串
     */
    public <T> String format(T obj) {
        return "FastJsonOutputFormater: " + JSON.toJSONString(obj);
    }
}

 

 

(5)自动配置类,用于向容器注册相应的对象:

关于Spring框架@Configuration使用,可参见博客《Spring:@Configuration 使用》

 

1)OutputFormaterAutoConfiguration:配置OutputFormater

 

这里通过@Conditional注解指定注册条件,主要用了:

 

@ConditionalOnMissingClass : classpath 中没有com.alibaba.fastjson.JSON 实例化,创建ToStringOutputFormater

@ConditionalOnClass(name = "com.alibaba.fastjson.JSON") classpath 中有com.alibaba.fastjson.JSON 实例化 FastJsonOutputFormater

package x.demo.springboot.starter.hw.autoconfiguration;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import x.demo.springboot.starter.hw.outputformater.FastJsonOutputFormater;
import x.demo.springboot.starter.hw.outputformater.OutputFormater;
import x.demo.springboot.starter.hw.outputformater.ToStringOutputFormater;

@Configuration
public class OutputFormaterAutoConfiguration {

    /**
     * @ConditionalOnMissingClass : classpath 中没有com.alibaba.fastjson.JSON 实例化,创建ToStringOutputFormater
     */
    @ConditionalOnMissingClass("com.alibaba.fastjson.JSON")
    @Bean
    public OutputFormater toStringOutputFormater() {
        return new ToStringOutputFormater();
    }

    /**
     * @ConditionalOnClass(name = "com.alibaba.fastjson.JSON") classpath 中有com.alibaba.fastjson.JSON 实例化 FastJsonOutputFormater
     */
    @ConditionalOnClass(name = "com.alibaba.fastjson.JSON")
    @Bean
    public OutputFormater fastJsonOutputFormater() {
        return new FastJsonOutputFormater();
    }
}

 

 

2)HelloWorldAutoConfiguration:配置HelloWorldTemplate

package x.demo.springboot.starter.hw.autoconfiguration;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import x.demo.springboot.starter.hw.HelloWorldTemplate;
import x.demo.springboot.starter.hw.outputformater.OutputFormater;


@EnableConfigurationProperties(HelloWorldProperties.class)
@Import(OutputFormaterAutoConfiguration.class)
@Configuration
public class HelloWorldAutoConfiguration {

    @Bean
    public HelloWorldTemplate helloWorldTemplate(HelloWorldProperties helloWorldProperties, OutputFormater outputFormater) {
        return new HelloWorldTemplate(helloWorldProperties, outputFormater);
    }
}

  

(6)注册自动配置类:META-INF/spring.factories

 

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
x.demo.springboot.starter.hw.autoconfiguration.HelloWorldAutoConfiguration

 

四 spring-boot-web 项目

(1)工程:

1)父 pom : 继承了spring-boot-starter-parent

 

<?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>x.demo.springboot.starter</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>module/spring-boot-helloworld-starter</module>
    </modules>

    <properties>
        <java.version>1.8</java.version>
        <spring.boot.version>1.5.9.RELEASE</spring.boot.version>
        <fastjson.version>1.2.28</fastjson.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- spring boot 基础依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>${fastjson.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>${java.version}</source>
                        <target>${java.version}</target>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

 

2)module: 

依赖下spring-boot-helloworld-starter,这里不依赖FastJson的包,则自定义Starter中实例化的是没 ToStringOutputFormater

<?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>x.demo.springboot</groupId>
        <artifactId>spring-boot</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>spring-boot-web</artifactId>
    <packaging>jar</packaging>

    <name>spring-boot-web</name>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>x.demo.springboot.starter</groupId>
            <artifactId>spring-boot-helloworld-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

 

(2)配置文件:application.yml

# 应用配置
server:
  port: 8080

# helloworld starter 配置
helloworld.author:
  name: foo
  roles: admin, developer
  email: foo@bar.com

 

(3)controller 调用 HelloWorldTemplate

package x.demo.springboot.web.controller;


import javax.annotation.Resource;

import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import x.demo.springboot.starter.hw.HelloWorldTemplate;

@RestController
@RequestMapping("/helloworld")
public class HelloWorldContorller {

    @Resource
    HelloWorldTemplate helloWorldTemplate;

    @GetMapping("/say")
    public String say() {
        String message = helloWorldTemplate.generate("------------");
        return StringUtils.replace(message,"\n","<br/>");
    }
}

 

(4)springboot启动类:

注:@SpringBootApplication 同时添加重要的两个MetaAnnotation @EnableAutoConfiguration,@ComponentScan,启动了AutoConfiguration和包扫描。

 

由于:

web包:x.demo.springboot.web

starter包:x.demo.springboot.starter.hw

 

包不同,所以Starter不是包扫描注入的,是通过读取META-INF/spring.factories注入的

 

package x.demo.springboot.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootWeb {

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

 

五 结果

1)常规结果

 

 

2)添加FastJson依赖的结果

web module 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>x.demo.springboot</groupId>
        <artifactId>spring-boot</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>spring-boot-web</artifactId>
    <packaging>jar</packaging>

    <name>spring-boot-web</name>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>x.demo.springboot.starter</groupId>
            <artifactId>spring-boot-helloworld-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
    </dependencies>
</project>

 



  

六 涉及注解说明

1) 配置

@Configuration,@Import,@Bean:《Spring:@Configuration 使用》

 

2) 条件组装

@ConditionalOnBean:Spring容器中存在指定实例时

@ConditionalOnClass:类加载器中存在指定类时

@ConditionalOnExpression:指定表达式成立时

@ConditionalOnMissingBean:Spring容器总缺少指定实例时

@ConditionalOnMissingClass:类加载器中不存在指定类时

@ConditionalOnNotWebApplication:非Web应用时

@ConditionalOnResource:存在指定资源文件时

@ConditionalOnWebApplication:Web应用时

 

3)读取属性

@EnableConfigurationProperties:开始扫描处理@ConfigurationProperties注解的Bean

@ConfigurationProperties:绑定外部配置

  • 大小: 75 KB
  • 大小: 80.3 KB
  • 大小: 319.6 KB
  • 大小: 215.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics