Spring Boot篇
一、Spring Boot简介
Spring Boot就是可以快速创建一个独立的、生产级的,基于Spring的应用程序。
在我看来,SpringBoot最大的优势就是使用starter来简化的Maven依赖配置和尽可能的自动配置。
特点:
- 创建独立的Spring应用程序
- 直接嵌入Tomcat,Jetty或Undertow(无需部署WAR文件)
- 提供自己的'入门'POM来简化你的Maven配置(在你创建一个spring boot应用程序时,会自动提供一些入门的pom依赖,从而简化依赖的配置)
- 尽可能自动配置Spring
- 提供生产就绪功能,如指标,运行状况检查和外部配置
- 绝对不会生成代码,并且不需要XML配置
对于SpringBoot中的尽可能的自动配置我们可以详细讲述一下。
(1)使用starter来简化你的Maven依赖配置
Spring提供了一系列starter来简化Maven配置。其核心原理也就是Maven和Gradle的依赖传递方案。当我们在我们的pom文件中增加对某个starter的依赖时,该starter的依赖也会自动的传递性被依赖进来。而且,很多starter也依赖了其他的starter。例如web starter就依赖了tomcat starter,并且大多数starter基本都依赖了spring-boot-starter。
(2)Spring自动配置
Spring Boot会根据类路径中的jar包、类,为jar包里的类自动配置,这样可以极大的减少配置的数量。简单点说就是它会根据定义在classpath下的类,自动的给你生成一些Bean,并加载到Spring的Context中。自动配置充分的利用了spring 4.0的条件化配置特性,能够自动配置特定的Spring bean,用来启动某项特性。
(3)条件化配置
假设你希望一个或多个bean只有在某种特殊的情况下才需要被创建,比如,一个应用同时服务于中美用户,要在中美部署,有的服务在美国集群中需要提供,在中国集群中就不需要提供。在Spring 4之前,要实现这种级别的条件化配置是比较复杂的,但是,Spring 4引入了一个新的@Conditional注解可以有效的解决这类问题。
@Bean
@Conditional(ChinaEnvironmentCondition.class)
public ServiceBean serviceBean(){
return new ServiceBean();
}
当@Conditional(ChinaEnvironmentCondition.class)
条件的值为true的时候,该ServiceBean才会被创建,否则该bean就会被忽略。
@Conditional指定了一个条件。他的条件的实现是一个Java类——ChinaEnvironmentCondition,要实现以上功能就要定义ChinaEnvironmentCondition类,并继承Condition接口并重写其中的matches方法。
class ChinaEnvironmentCondition implements Condition{
public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
return env.containProperty("ENV_CN");
}
}
在上面的代码中,matches方法的内容比较简单,他通过给定的ConditionContext对象进而获取Environment对象,然后使用该对象检查环境中是否存在ENV_CN属性。如果存在该方法则直接返回true,反之返回false。当该方法返回true的时候,就符合了@Conditional指定的条件,那么ServiceBean就会被创建。反之,如果环境中没有这个属性,那么这个ServiceBean就不会被创建。
除了可以自定义一些条件之外,Spring 4本身提供了很多已有的条件供直接使用,如:
@ConditionalOnBean
@ConditionalOnClass
@ConditionalOnExpression
@ConditionalOnMissingBean
@ConditionalOnMissingClass
@ConditionalOnNotWebApplication
(4)Spring应用的启动入口
自动配置充分的利用了spring 4.0的条件化配置特性,那么,Spring Boot是如何实现自动配置的?Spring 4中的条件化配置又是怎么运用到Spring Boot中的呢?
这要从Spring Boot的启动类说起。Spring Boot应用通常有一个名为*Application的入口类,入口类中有一个main方法,这个方法其实就是一个标准的Java应用的入口方法。一般在main方法中使用SpringApplication.run()
来启动整个应用。
值得注意的是,这个入口类要使用@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 {
// 略
}
@SpringBootApplication是一个组合注解,它主要包含@SpringBootConfiguration、@EnableAutoConfiguration等几个注解。也就是说可以直接在启动类中使用这些注解来代替@ SpringBootApplication注解。 关于Spring Boot中的Spring自动化配置主要是@EnableAutoConfiguration的功劳。该注解可以让Spring Boot根据类路径中的jar包依赖为当前项目进行自动配置。
至此,我们知道,Spring Boot的自动化配置主要是通过@EnableAutoConfiguration来实现的,因为我们在程序的启动入口使用了@SpringBootApplication注解,而该注解中组合了@EnableAutoConfiguration注解。所以,在启动类上使用@EnableAutoConfiguration注解,就会开启自动配置。
那么,本着刨根问底的原则,当然要知道@EnableAutoConfiguration又是如何实现自动化配置的,因为目前为止,我们还没有发现Spring 4中条件化配置的影子。
(5)EnableAutoConfiguration注解
其实Spring框架本身也提供了几个名字为@Enable开头的Annotation定义。比如@EnableScheduling、@EnableCaching、@EnableMBeanExport等,@EnableAutoConfiguration的理念和这些注解其实是一脉相承的。
- @EnableScheduling是通过@Import将Spring调度框架相关的bean定义都加载到IoC容器。
- @EnableMBeanExport是通过@Import将JMX相关的bean定义加载到IoC容器。
- @EnableAutoConfiguration也是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器。
下面是EnableAutoConfiguration注解的源码:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
//略
}
观察@EnableAutoConfiguration可以发现,这里Import了@EnableAutoConfigurationImportSelector,这就是Spring Boot自动化配置的“始作俑者”。
至此,我们知道,至此,我们知道,由于我们在Spring Boot的启动类上使用了@SpringBootApplication注解,而该注解组合了@EnableAutoConfiguration注解,@EnableAutoConfiguration是自动化配置的“始作俑者”,而@EnableAutoConfiguration中Import了@EnableAutoConfigurationImportSelector注解,该注解的内部实现已经很接近我们要找的“真相”了。
(6)EnableAutoConfigurationImportSelector
EnableAutoConfigurationImportSelector的源码在这里就不贴了,其实实现也比较简单,主要就是使用Spring 4 提供的的SpringFactoriesLoader工具类。
通过SpringFactoriesLoader.loadFactoryNames()
读取了ClassPath下面的META-INF/spring.factories文件。
这里要简单提一下spring.factories文件,它是一个典型的java properties文件,配置的格式为Key = Value形式。
EnableAutoConfigurationImportSelector通过读取spring.factories
中的key为org.springframework.boot.autoconfigure.EnableAutoConfiguration
的值。如spring-boot-autoconfigure-1.5.1.RELEASE.jar中的spring.factories文件包含以下内容:
# Auto Configure
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,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
......
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
上面的EnableAutoConfiguration配置了多个类,这些都是Spring Boot中的自动配置相关类;在启动过程中会解析对应类配置信息。每个Configuation都定义了相关bean的实例化配置。都说明了哪些bean可以被自动配置,什么条件下可以自动配置,并把这些bean实例化出来。
如果我们新定义了一个starter的话,也要在该starter的jar包中提供 spring.factories文件,并且为其配置org.springframework.boot.autoconfigure.EnableAutoConfiguration
对应的配置类。
(7)Configuation
@Configuration
@AutoConfigureAfter({JmxAutoConfiguration.class})
@ConditionalOnProperty(
prefix = "spring.application.admin",
value = {"enabled"},
havingValue = "true",
matchIfMissing = false
)
public class SpringApplicationAdminJmxAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public SpringApplicationAdminMXBeanRegistrar springApplicationAdminRegistrar() throws MalformedObjectNameException {
String jmxName = this.environment.getProperty("spring.application.admin.jmx-name", "org.springframework.boot:type=Admin,name=SpringApplication");
if(this.mbeanExporter != null) {
this.mbeanExporter.addExcludedBean(jmxName);
}
return new SpringApplicationAdminMXBeanRegistrar(jmxName);
}
}
看到上面的代码,终于找到了我们要找的东西——Spring 4的条件化配置。上面SpringApplicationAdminJmxAutoConfiguration在决定对哪些bean进行自动化配置的时候,使用了两个条件注解:ConditionalOnProperty和ConditionalOnMissingBean。只有满足这种条件的时候,对应的bean才会被创建。这样做的好处是什么?这样可以保证某些bean在没满足特定条件的情况下就可以不必初始化,避免在bean初始化过程中由于条件不足,导致应用启动失败。
通过Spring 4的条件配置决定哪些bean可以被配置,将这些条件定义成具体的Configuation,然后将这些Configuation配置到spring.factories文件中,作为key: org.springframework.boot.autoconfigure.EnableAutoConfiguration
的值,这时候,容器在启动的时候,由于使用了EnableAutoConfiguration注解,该注解Import的EnableAutoConfigurationImportSelector会去扫描classpath下的所有spring.factories文件,然后进行bean的自动化配置。
所以,如果我们想要自定义一个starter的话,可以通过以上方式将自定义的starter中的bean自动化配置到Spring的上下文中,从而避免大量的配置。
以上就是spring boot尽可能自动配置这个特点的讲解。
二、spring boot项目快速开始
下面我们开始创建一个spring boot项目,也就是我们经常所写的HelloWorld
第一步:点击File->New->Project
第二步:选择Spring Initializr创建spring boot项目
第三步:填写项目唯一标识:GroupId和Artifact,Version版本号等等信息
GroupId:一般为域名加公司名,域名一般为com,org,cn;com一般为商业组织,org一般为非营利组织,cn为中国域名,Artifact要注意不要包含非法字符,如大写字母。
总之,要保证你的项目名唯一。
第四步:写上项目名比如SpringBootHelloWorld,选择好存放路径。点击Finish后即可。
创建完成后我们可以发现,spring boot 项目提供了入门的pom来简化你的Maven配置,SpringBoot项目<parent>依赖,测试依赖等等,启动类上也可以看到@SpringBootApplication注解,这个是SpringBoot项目的核心注解,可以尽可能的为你自动配置。
package com.example.springboothelloworld;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringboothelloworldApplication {
public static void main(String[] args) {
SpringApplication.run(SpringboothelloworldApplication.class, args);
}
}
三、运行项目
在运行项目之前我们可以需要将SpringBoot官网上面提供的依赖添加进来,这个是开启Web项目的依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
添加好后,我们可以写一个测试代码
我是在启动类当前包下右新建了一个包,包的名字就叫controller,新建了一个SampleController类
然后SampleController类就可以添加如下代码:
package com.example.springboothelloworld.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by sunwei on 2018-03-13 Time:14:16:24
*/
@RestController
@RequestMapping(value = "/demo")
public class SampleController {
@RequestMapping(value = "/helloWorld",method = RequestMethod.GET)
public String helloWorld(){
return "HelloWorld";
}
}
注意:在这里我没有用springboot官网提供的@Controller和@ResponseBody注解,而是用了@RestController注解,@RestController这个注解是一个组合注解,我们可以看一下该注解的源码。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Controller;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(
annotation = Controller.class
)
String value() default "";
}
从源码里面我们可以看到,这个注解其实就是
@Controller @ResponseBody
这两个注解的组合,所以我在这里就使用了这一个注解,在下面的接口函数上我就不用添加
@ResponseBody
注解了,添加好代码后,我们还需要在application.properties文件里面配置下端口号,如果不进行配置的话,系统会默认为8080,我配置的是8888端口。
启动后,可以看到端口号变成了8888
启动完成后,我们可以在浏览器中输入localhost:8888/demo/HelloWorld
就可以看到如下的响应了
好了,以上就是springboot的入门
具体项目可以查看我的github: 点击打开链接