01 Spring Boot 核心

来源:互联网 发布:爱奇艺视频转换器mac版 编辑:程序博客网 时间:2024/06/06 19:27

1 基本配置

1.1 @SpringBootApplication

@SpringBootApplication是Spring-Boot核心注解,是一个组合注解,源码如下:

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(    excludeFilters = {@Filter(    type = FilterType.CUSTOM,    classes = {TypeExcludeFilter.class}), @Filter(    type = FilterType.CUSTOM,    classes = {AutoConfigurationExcludeFilter.class})})public @interface SpringBootApplication {    @AliasFor(        annotation = EnableAutoConfiguration.class,        attribute = "exclude"    )    Class<?>[] exclude() default {};    @AliasFor(        annotation = EnableAutoConfiguration.class,        attribute = "excludeName"    )    String[] excludeName() default {};    @AliasFor(        annotation = ComponentScan.class,        attribute = "basePackages"    )    String[] scanBasePackages() default {};    @AliasFor(        annotation = ComponentScan.class,        attribute = "basePackageClasses"    )    Class<?>[] scanBasePackageClasses() default {};}

@EnableAutoConfiguration让Spring Boot根据类路径下的jar包依赖,为当前项目进行自动配置。

例如,添加了spring-boot-starter-web依赖,会自动添加Tomcat和SpringMVC的依赖,那么Spring Boot会对Tomcat和SpringMVC进行自动配置。

又如,添加了spring-boot-starter-data-jpa依赖,Spring Boot会自动进行JPA的配置。

Spring Boot会自动扫描@SpringBootApplication所在类的同级包(如,com.wisely.ch5_2_2)以及下级包里的Bean(若为jpa项目还可以扫描标注@Entity的实体类),

1.2 关闭特定的自动配置

通过@SpringBootApplication注解的源码可以发现,关闭特定的配置应该使用@SpringBootApplication注解的exclude参数,例如:

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

1.3 定制Banner

(1)修改Banner

在src/main/resource 下新建banner.txt,将在网站http://patorjk.com/software/taag/生成字符粘贴到该文档。

(2)关闭Banner

修改main

public static void main(String[] args) {    SpringApplication app = new SpringApplication(Ch522Application.class);    app.setBannerMode(Mode.OFF);    app.run(args);}

1.4 Spring Boot 配置文件

Spring Boot 使用一个全局配置文件application.properties 或 application.yml,src/main/resource 或类路径的/config下面。

Spring Boot 全局配置文件的作用是对一些默认的配置进行修改,如修改端口号和默认的访问路径,可以在application.properties中添加如下:

server.port=8081server.servlet.context-path=/helloboot

1.5 starter pom

Spring Boot 为我们提供了简化企业开发绝大多数场景的starter pom,只要使用应用场景所需的starter pom,相关的技术配置就会消除。

下面的应用程序starters是Spring Boot在org.springframework.boot组下提供的:

Spring Boot application starters

名称 描述 spring-boot-starter 核心Spring Boot starter,包括自动配置支持,日志和YAML spring-boot-starter-actuator 生产准备的特性,用于帮你监控和管理应用 spring-boot-starter-amqp 对”高级消息队列协议”的支持,通过spring-rabbit实现 spring-boot-starter-aop 对面向切面编程的支持,包括spring-aop和AspectJ spring-boot-starter-batch 对Spring Batch的支持,包括HSQLDB数据库 spring-boot-starter-cloud-connectors 对Spring Cloud Connectors的支持,简化在云平台下(例如,Cloud Foundry 和Heroku)服务的连接 spring-boot-starter-data-elasticsearch 对Elasticsearch搜索和分析引擎的支持,包括spring-data-elasticsearch spring-boot-starter-data-gemfire 对GemFire分布式数据存储的支持,包括spring-data-gemfire spring-boot-starter-data-jpa 对”Java持久化API”的支持,包括spring-data-jpaspring-orm和Hibernate spring-boot-starter-data-mongodb 对MongoDB NOSQL数据库的支持,包括spring-data-mongodb spring-boot-starter-data-rest 对通过REST暴露Spring Data仓库的支持,通过spring-data-rest-webmvc实现 spring-boot-starter-data-solr 对Apache Solr搜索平台的支持,包括spring-data-solr spring-boot-starter-freemarker 对FreeMarker模板引擎的支持 spring-boot-starter-groovy-templates 对Groovy模板引擎的支持 spring-boot-starter-hateoas 对基于HATEOAS的RESTful服务的支持,通过spring-hateoas实现 spring-boot-starter-hornetq 对”Java消息服务API”的支持,通过HornetQ实现 spring-boot-starter-integration 对普通spring-integration模块的支持 spring-boot-starter-jdbc 对JDBC数据库的支持 spring-boot-starter-jersey 对Jersey RESTful Web服务框架的支持 spring-boot-starter-jta-atomikos 对JTA分布式事务的支持,通过Atomikos实现 spring-boot-starter-jta-bitronix 对JTA分布式事务的支持,通过Bitronix实现 spring-boot-starter-mail 对javax.mail的支持 spring-boot-starter-mobile 对spring-mobile的支持 spring-boot-starter-mustache 对Mustache模板引擎的支持 spring-boot-starter-redis 对REDIS键值数据存储的支持,包括spring-redis spring-boot-starter-security 对spring-security的支持 spring-boot-starter-social-facebook 对spring-social-facebook的支持 spring-boot-starter-social-linkedin 对spring-social-linkedin的支持 spring-boot-starter-social-twitter 对spring-social-twitter的支持 spring-boot-starter-test 对常用测试依赖的支持,包括JUnit, Hamcrest和Mockito,还有spring-test模块 spring-boot-starter-thymeleaf 对Thymeleaf模板引擎的支持,包括和Spring的集成 spring-boot-starter-velocity 对Velocity模板引擎的支持 spring-boot-starter-web 对全栈web开发的支持,包括Tomcat和spring-webmvc spring-boot-starter-websocket 对WebSocket开发的支持 spring-boot-starter-ws 对Spring Web服务的支持

除了应用程序的starters,下面的starters可以用于添加[生产准备](../V. Spring Boot Actuator/README.md)的特性。

Spring Boot生产准备的starters

名称 描述 spring-boot-starter-actuator 添加生产准备特性,比如指标和监控 spring-boot-starter-remote-shell 添加远程ssh shell支持

最后,Spring Boot包含一些可用于排除或交换具体技术方面的starters。

Spring Boot technical starters

名称 描述 spring-boot-starter-jetty 导入Jetty HTTP引擎(作为Tomcat的替代) spring-boot-starter-log4j 对Log4J日志系统的支持 spring-boot-starter-logging 导入Spring Boot的默认日志系统(Logback) spring-boot-starter-tomcat 导入Spring Boot的默认HTTP引擎(Tomcat) spring-boot-starter-undertow 导入Undertow HTTP引擎(作为Tomcat的替代)

1.6 使用xml进行配置

Spring Boot 提倡零配置,即无xml配置,但在实际项目中可能有些特殊要求你必须使用xml配置,这是我们通过Spring提供的@ImportResource来加载xml配置,例如:

@ImportResource({“classpath:some-context.xml”,”classpath:another-context.xml”})

2 外部配置

Spring Boot 允许使用xml、yaml和命令行参数作为外部配置。

2.1 命令行参数配置

命令行参数是在jar包启动的时候输入
Spring Boot 是基于jar运行的,jar启动命令:

java -jar xx.jar

可以通过下面命令修改tomcat短口号:

java -jar xx.jar –server.port=9090

2.2 常规属性配置

在常规Spring环境下,注入property文件里值的方式,通过@PropertySource指明property的位置,然后通过@Value注入值。在Spring Boot中,只需要在application.properties中定义属性,直接使用@Value注入即可。

实战:

(1)在application.properties增加如下属性:

book.author=iwillbook.name=spring boot

(2)修改入口类

@RestControllerpublic class Controller {    @Value("${book.author}")    private String boolAuthor;    @Value("${book.name}")    private String boolName;    @RequestMapping("/")    String index() {        return "The book name is "  + boolName + ", the book author is " + boolAuthor;    }}

2.3 类型安全的配置(基于properties)

上面使用@Value注入每个属性,显得格外麻烦,Spring Boot还提供了基于类型的安全配置方式,通过@ConfigurationProperties将properties属性和一个bean的属性关联,从而实现类型安全配置。

实战:

(1)新建Spring Boot项目ch6_2_3

(2)在application.properties中添加:

author.name=iwillauhtor.age=27

当然,也可以新建一个properties文件,这就需要使用@ConfigurationProperties的location属性指定properties文件位置,且需要在入口类上配置。

spring boot 1.5以上版本@ConfigurationProperties取消location注解,解决方案如下:

  • 在@EnableConfigurationProperties取消激活自定义的配置类(重要)
  • 在配置类中采用@Component的方式注册为组件,然后使用@PropertySource来指定自定义的资源目录

    (3)类型安全的bean
@Component@ConfigurationProperties(prefix = "author")@PropertySource("classpath:/config/bean.properties")public class AuthorSettings {    private String name;    private Long age;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Long getAge() {        return age;    }    public void setAge(Long age) {        this.age = age;    }}

(4)检验代码

@RestControllerpublic class AppController {    @Autowired    private AuthorSettings authorSettings;    @RequestMapping("/")    public String index() {        return "The author name is " + authorSettings.getName() + ",the author age is " + authorSettings.getAge();    }}

3 日志配置

Spring Boot支持Java Util Logging、log4j、log4j2和Logback作为日志框架,无论使用哪种日志框架,Spring Boot已为当前使用框架的控制台输出和文件输出做好了做好了配置。

4 Profile 配置

Profile是spring针对不同环境对不同的配置提供支持的,全局Profile使用application-{profile}.properties,如(application-prod.properties)。

通过在application.properties中设置spring-profile-active=prod来指定活动的profile。

如生产和开发环境配置文件如下:

application-prod.properties

server.port=8081

application-dev.properties

server.port=80

可以指定要使用的配置文件
application.properties

spring.profiles.active=prod

5 Spring Boot 运行原理

要想直到Spring Boot为我们做了哪些自动配置,看查看下面这些源码

可以通过一下三种方式查看已启动的和未启动的配置报告
(1)运行jar文件增加debug参数

java -jar xx.jar --debug

(2)在application.properties中增加属性

debug=true

(3)配置启动参数

5.1 运行原理

关于Spring Boot 运行原理还是回归到@SpringBootApplication注解上来,它的核心功能是由@EnableAutoConfiguration注解提供的。

@EnableAutoConfiguration注解源码如下:

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import({AutoConfigurationImportSelector.class})public @interface EnableAutoConfiguration {    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";    Class<?>[] exclude() default {};    String[] excludeName() default {};}

这里关键是@import注解的导入功能,AutoConfigurationImportSelector使用

List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());

方法来扫描具有META-INF/spring.factories文件的jar包,而spring-boot-autoconfigure-2.x.x.jar就包含一个spring.factories文件,此文件生命了有哪些自动配置,如下(里面有个# AutoConfigure):

5.2 核心注解

  • @ConditionalOnBean 当容器里有指定Bean的条件下。
  • @ConditionalOnClass 当路径下有指定类的条件下。
  • @ConditionalOnExpression 基于SpEL表达式作为判断条件
  • @ConditionalOnJava 基于JVM版本作为判断条件。
  • @ConditionalOnJndi 在JNDI存在的条件下查找指定位置。
  • @ConditionalOnMissingBean 当容器里没有指定Bean的情况下。
  • @ConditionalOnMissingClass 当路径没有指定类的情况下。
  • @ConditionalOnNotWebApplication 当项目不是web项目的条件下。
  • @ConditionalOnProperty 指定的属性是否有指定的值。
  • @ConditionalOnResource 类路径是否有指定的值。
  • @ConditionalOnSingleCondidate 当指定Bean在容器中只有一个,或虽然由多个但指定首选Bean。
  • @ConditionalOnWebApplication 当前项目是web项目的条件下。

下面分析@ConditionalOnWebApplication注解。

@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documented@Conditional({OnWebApplicationCondition.class})public @interface ConditionalOnWebApplication {    ConditionalOnWebApplication.Type type() default ConditionalOnWebApplication.Type.ANY;    public static enum Type {        ANY,        SERVLET,        REACTIVE;        private Type() {        }    }}

从源码可以看出,此注解使用的条件OnWebApplicationCondition,下面介绍这个条件是如何构造的:

import java.util.Map;import org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;import org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext;import org.springframework.context.annotation.ConditionContext;import org.springframework.core.annotation.Order;import org.springframework.core.type.AnnotatedTypeMetadata;import org.springframework.util.ClassUtils;import org.springframework.util.ObjectUtils;import org.springframework.web.context.ConfigurableWebEnvironment;import org.springframework.web.context.WebApplicationContext;@Order(-2147483628)class OnWebApplicationCondition extends SpringBootCondition {    private static final String WEB_CONTEXT_CLASS = "org.springframework.web.context.support.GenericWebApplicationContext";    OnWebApplicationCondition() {    }    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {        boolean required = metadata.isAnnotated(ConditionalOnWebApplication.class.getName());        ConditionOutcome outcome = this.isWebApplication(context, metadata, required);        if (required && !outcome.isMatch()) {            return ConditionOutcome.noMatch(outcome.getConditionMessage());        } else {            return !required && outcome.isMatch() ? ConditionOutcome.noMatch(outcome.getConditionMessage()) : ConditionOutcome.match(outcome.getConditionMessage());        }    }    private ConditionOutcome isWebApplication(ConditionContext context, AnnotatedTypeMetadata metadata, boolean required) {        Builder message = ConditionMessage.forCondition(ConditionalOnWebApplication.class, new Object[]{required ? "(required)" : ""});        Type type = this.deduceType(metadata);        if (Type.SERVLET == type) {            return this.isServletWebApplication(context);        } else if (Type.REACTIVE == type) {            return this.isReactiveWebApplication(context);        } else {            ConditionOutcome servletOutcome = this.isServletWebApplication(context);            if (servletOutcome.isMatch() && required) {                return new ConditionOutcome(servletOutcome.isMatch(), message.because(servletOutcome.getMessage()));            } else {                ConditionOutcome reactiveOutcome = this.isReactiveWebApplication(context);                if (reactiveOutcome.isMatch() && required) {                    return new ConditionOutcome(reactiveOutcome.isMatch(), message.because(reactiveOutcome.getMessage()));                } else {                    boolean finalOutcome = required ? servletOutcome.isMatch() && reactiveOutcome.isMatch() : servletOutcome.isMatch() || reactiveOutcome.isMatch();                    return new ConditionOutcome(finalOutcome, message.because(servletOutcome.getMessage()).append("and").append(reactiveOutcome.getMessage()));                }            }        }    }    private ConditionOutcome isServletWebApplication(ConditionContext context) {        Builder message = ConditionMessage.forCondition("", new Object[0]);        if (!ClassUtils.isPresent("org.springframework.web.context.support.GenericWebApplicationContext", context.getClassLoader())) {            return ConditionOutcome.noMatch(message.didNotFind("web application classes").atAll());        } else {            if (context.getBeanFactory() != null) {                String[] scopes = context.getBeanFactory().getRegisteredScopeNames();                if (ObjectUtils.containsElement(scopes, "session")) {                    return ConditionOutcome.match(message.foundExactly("'session' scope"));                }            }            if (context.getEnvironment() instanceof ConfigurableWebEnvironment) {                return ConditionOutcome.match(message.foundExactly("ConfigurableWebEnvironment"));            } else {                return context.getResourceLoader() instanceof WebApplicationContext ? ConditionOutcome.match(message.foundExactly("WebApplicationContext")) : ConditionOutcome.noMatch(message.because("not a servlet web application"));            }        }    }    private ConditionOutcome isReactiveWebApplication(ConditionContext context) {        Builder message = ConditionMessage.forCondition("", new Object[0]);        return context.getResourceLoader() instanceof ReactiveWebApplicationContext ? ConditionOutcome.match(message.foundExactly("ReactiveWebApplicationContext")) : ConditionOutcome.noMatch(message.because("not a reactive web application"));    }    private Type deduceType(AnnotatedTypeMetadata metadata) {        Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnWebApplication.class.getName());        return attributes != null ? (Type)attributes.get("type") : Type.ANY;    }}

从isOnWebApplication可以看出,判断条件是:
(1)GenericWebApplicationContext是否在类路径中
(2)容器里是否有名为session的scope
(3)当前容器Environment是否为StandardServletEnvironment
(4)当前的ResourceLoader是否为WebApplicationContext(ResourceLoader是ApplicationContext的顶级接口之一)
(5)我们需要构造ConditionOutCome类的对象来帮助我们,最终通过ConditionOutcome.isMatch返回的布尔值来确定条件。

5.3 实例分析

分析一个简单的Spring Boot 自动配置功能:http编码配置。

常规web项目配置http编码是在web.xml中配置一个filter,如下:

<filter>    <filter-name>encoding</filter-name>    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>    <init-param>        encoding        UTF-8    </init-param></filter><filter-mapping>    <filter-name>encoding</filter-name>    <url-pattern>/*</url-pattern></filter-mapping>

Spring Boot这一点是基于类型安全配置实现的,可以在application.properties中直接设置,具体源码如下:

@ConfigurationProperties(    prefix = "spring.http.encoding")public class HttpEncodingProperties {    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");    private Charset charset;    private Boolean force;    private Boolean forceRequest;    private Boolean forceResponse;    private Map<Locale, Charset> mapping;    public HttpEncodingProperties() {        this.charset = DEFAULT_CHARSET;    }    public Charset getCharset() {        return this.charset;    }    public void setCharset(Charset charset) {        this.charset = charset;    }    public boolean isForce() {        return Boolean.TRUE.equals(this.force);    }    public void setForce(boolean force) {        this.force = force;    }    public boolean isForceRequest() {        return Boolean.TRUE.equals(this.forceRequest);    }    public void setForceRequest(boolean forceRequest) {        this.forceRequest = forceRequest;    }    public boolean isForceResponse() {        return Boolean.TRUE.equals(this.forceResponse);    }    public void setForceResponse(boolean forceResponse) {        this.forceResponse = forceResponse;    }    public Map<Locale, Charset> getMapping() {        return this.mapping;    }    public void setMapping(Map<Locale, Charset> mapping) {        this.mapping = mapping;    }    public boolean shouldForce(HttpEncodingProperties.Type type) {        Boolean force = type == HttpEncodingProperties.Type.REQUEST ? this.forceRequest : this.forceResponse;        if (force == null) {            force = this.force;        }        if (force == null) {            force = type == HttpEncodingProperties.Type.REQUEST;        }        return force.booleanValue();    }    public static enum Type {        REQUEST,        RESPONSE;        private Type() {        }    }}

通过上述配置,并根据条件配置Character.Encording.Filter的Bean,源码如下:

@Configuration@EnableConfigurationProperties({HttpEncodingProperties.class})@ConditionalOnWebApplication(    type = Type.SERVLET)@ConditionalOnClass({CharacterEncodingFilter.class})@ConditionalOnProperty(    prefix = "spring.http.encoding",    value = {"enabled"},    matchIfMissing = true)public class HttpEncodingAutoConfiguration {    private final HttpEncodingProperties properties;    public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {        this.properties = properties;    }    @Bean    @ConditionalOnMissingBean({CharacterEncodingFilter.class})    public CharacterEncodingFilter characterEncodingFilter() {        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();        filter.setEncoding(this.properties.getCharset().name());        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type.REQUEST));        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type.RESPONSE));        return filter;    }    @Bean    public HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {        return new HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer(this.properties);    }    private static class LocaleCharsetMappingsCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {        private final HttpEncodingProperties properties;        LocaleCharsetMappingsCustomizer(HttpEncodingProperties properties) {            this.properties = properties;        }        public void customize(ConfigurableServletWebServerFactory webServerFactory) {            if (this.properties.getMapping() != null) {                webServerFactory.setLocaleCharsetMappings(this.properties.getMapping());            }        }        public int getOrder() {            return 0;        }    }}

5.4 实战

包含当某个类存在时,自动配置这个类的Bean,并可将Bean的属性在application.properties中配置。

(1)新建Maven项目,修改pom文件如下(增加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>com.wisely</groupId>    <artifactId>spring-boot-starter-hello</artifactId>    <version>1.0-SNAPSHOT</version>    <packaging>jar</packaging>    <name>spring-boot-starter-hello</name>    <url>http://maven.apache.org</url>    <properties>        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>    </properties>    <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-autoconfigure</artifactId>            <version>2.0.0.BUILD-SNAPSHOT</version>        </dependency>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>3.8.2</version>            <scope>test</scope>        </dependency>    </dependencies>    <!-- 使用Spring Boot 正式版时,无须下列配置 -->    <repositories>        <repository>            <id>spring-snapshots</id>            <name>Spring Snapshots</name>            <url>https://repo.spring.io/snapshot</url>;            <snapshots>                <enabled>true</enabled>            </snapshots>        </repository>        <repository>            <id>spring-milestones</id>            <name>Spring Milestones</name>            <url>https://repo.spring.io/milestone</url>;            <snapshots>                <enabled>false</enabled>            </snapshots>        </repository>    </repositories>    <pluginRepositories>        <pluginRepository>            <id>spring-snapshots</id>            <name>Spring Snapshots</name>            <url>https://repo.spring.io/snapshot</url>;            <snapshots>                <enabled>true</enabled>            </snapshots>        </pluginRepository>        <pluginRepository>            <id>spring-milestones</id>            <name>Spring Milestones</name>            <url>https://repo.spring.io/milestone</url>;            <snapshots>                <enabled>false</enabled>            </snapshots>        </pluginRepository>    </pluginRepositories></project>

(2)属性配置

@ConfigurationProperties(prefix = "hello")public class HelloServiceProperties {    private static final String MSG = "world";    private String msg = MSG;    public String getMsg() {        return msg;    }    public void setMsg(String msg) {        this.msg = msg;    }}

(3)判断依据类(根据此类是否存在来创建这个类的Bean,这个类可以是第三方类库)

public class HelloService {    private String msg;    public String sayHello() {        return "Hello " + msg;     }    public String getMsg() {        return msg;    }    public void setMsg(String msg) {        this.msg = msg;    }}

(4)自动配置类

@Configuration@EnableConfigurationProperties(HelloServiceProperties.class)@ConditionalOnClass(HelloService.class)@ConditionalOnProperty(prefix = "hello",value = {"enabled"}, matchIfMissing = true)public class HelloServiceAutoConfiguration {    @Autowired    private HelloServiceProperties helloServiceProperties;    @Bean    @ConditionalOnMissingBean(HelloService.class)    public HelloService helloService() {        HelloService helloService = new HelloService();        helloService.setMsg(helloServiceProperties.getMsg());        return helloService;    }}

代码解释:

根据HelloServiceProperties提供的参数,并通过@ConditionalOnClass判断HelloService这个类在类路径中是否存在,且当容器中没有这个Bean的情况下自动配置这个Bean。
(5)注册配置。在src/main/resources下新建META-INF/spring.factories,填写如下内容:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\  com.wisely.autoconfigure.HelloServiceAutoConfiguration

若有多个配置用逗号隔开。
(6)使用上面创建的starter,新建Spring Boot项目,并将starter作为依赖。

<dependency>    <groupId>com.wisely</groupId>    <artifactId>spring-boot-starter-hello</artifactId>    <version>1.0-SNAPSHOT</version></dependency>

运行类代码如下:

@RestController@SpringBootApplicationpublic class Ch65Application {    @Autowired    private HelloService helloService;    @RequestMapping("/")    public String index() {        return helloService.sayHello();    }    public static void main(String[] args) {        SpringApplication.run(Ch65Application.class, args);    }}

在application.properties中添加配置msg的内容

hello.msg=iwill
原创粉丝点击