SpringBoot
用来简化Spring
应用开发,约定大于配置,去繁从简,是由Pivotal
团队提供的全新框架。其设计目的是用来简化新Spring
应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置(有特殊需求可以添加自己的配置覆盖默认配置),从而使开发人员不再需要定义样板化的配置。SpringBoot
可以看成是J2EE
的一站式解决方案。
一、SpringBoot 的优点
【1】快速创建独立运行的Spring
项目以及与主流框架集成。
【2】使用嵌入式的Servlet
容器,应用无需打成war
包,可以打成jar
包,通过java -jar
的方式直接运行。
【3】starters
(启动器)自动依赖与版本控制。
【4】大量的自动配置,简化开发,也可以修改默认值。
【5】无需配置XML
,无代码生成,开箱即用。
【6】准生产环境的运行时应用监控。
【7】与云计算的天然集成。
二、解决微服务部署和运维难的问题:Spring Boot
如上的流程依次为: 搭建项目 构建连接 批处理
三、Spring Boot 入门项目
HelloWorld(也可以参考五,快速创建一个 SpringBoot项目)
【1】准备环境: 为Maven
的settings.xml
配置文件的profiles
标签添加如下信息:
profile>
id>jdk-1.8id>
activation>
activeByDefault>trueactiveByDefault>
jdk>1.8jdk>
activation>
properties>
maven.compiler.source>1.8maven.compiler.source>
maven.compiler.target>1.8maven.compiler.target>
maven.compiler.compilerVersion>1.8maven.compiler.compilerVersion>
properties>
profile>
【2】将IDEA
的 Maven
更换为我们自己本地安装的Maven
。(自行百度更换)创建一个maven
工程[jar
],在pom.xml
中导入如下依赖:
parent>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-starter-parentartifactId>
version>2.0.0.RELEASEversion>
parent>
dependencies>
dependency>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
【3】编写一个主程序,启动SpringBoot
应用
@SpringBootApplication
public class Hello {
public static void main(String[] args) throws Exception {
//启动spring应用
SpringApplication.run(Hello.class, args);
}
}
【4】编写相关的Controller
、Service
类
@Controller
public class HelloController {
@ResponseBody
@RequestMapping("/hello")
public String hello(){
return "hello world!";
}
}
【5】运行主测试程序。简化部署应用jar包>:通过Maven Projects
中 的package
(双击)即可。生成jar
的位置:默认在项目的target
目录下的“项目名称.jar
”文件。运行jar
:在命令行可以通过 “java -jar jar文件名.jar
” 命令运行项目。
build>
plugins>
plugin>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
四、Hello World 探究(POM文件)
【1】父项目[spring-boot-starter-parent
]:
parent>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-starter-parentartifactId>
version>2.0.0.RELEASEversion>
parent>
【2】进入spring-boot-starter-parent
发现它还有一个父项目 :
parent>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-dependenciesartifactId>
version>2.0.0.RELEASEversion>
relativePath>../../spring-boot-dependenciesrelativePath>
parent>
【3】进入spring-boot-dependencies
后,发现如下信息,与之前我们创建的分布式项目继承的Maven
父项目功能是一样的,用来管理所有jar
包依赖的版本。称为SpringBoot
的版本仲裁中心,以后我们导入依赖默认是不需要写版本;(没有在dependencies
里面管理的依赖,需要声明版本号)
properties>
activemq.version>5.15.3activemq.version>
antlr2.version>2.7.7antlr2.version>
appengine-sdk.version>1.9.62appengine-sdk.version>
artemis.version>2.4.0artemis.version>
aspectj.version>1.8.13aspectj.version>
assertj.version>3.9.1assertj.version>
... 此处省略 .../>
properties>
【4】启动器[spring-boot-starter-web
]
dependency>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-starter-webartifactId>
dependency>
spring-boot-starter-web
:spring-boot-starter
指spring-boot
场景启动器;进入官网可以到有许多场景启动器,简单点说就是通过此功能将相关jar
包给组合在起来,我们使用时只需要引入一个Web Starter
就可以轻松搞定。Spring Boot
将所有的功能场景都抽取出来,做成一个个的 starters
(启动器),只需要在项目里面引入这些starter
相关场景,所有依赖都会导入进来。要用什么功能就导入什么场景启动器。
点击web
右边的pom
可以看到SpringBoot
为我们依赖的其它jar
包,帮我们导入了web
模块正常运行所依赖的所有组件。如下:
dependencies>
dependency>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-starterartifactId>
dependency>
dependency>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-starter-tomcatartifactId>
dependency>
dependency>
groupId>org.hibernategroupId>
artifactId>hibernate-validatorartifactId>
dependency>
dependency>
groupId>com.fasterxml.jackson.coregroupId>
artifactId>jackson-databindartifactId>
dependency>
dependency>
groupId>org.springframeworkgroupId>
artifactId>spring-webartifactId>
dependency>
dependency>
groupId>org.springframeworkgroupId>
artifactId>spring-webmvcartifactId>
dependency>
dependencies>
【5】主程序类(Java
类):@SpringBootApplication
:此注解声明的类,是SpringBoot
的主配置类,SpringBoot
就应该运行这个类的main
方法来启动SpringBoot
。
//@ImportResource(locations={"classpath:bean.xml"})
//@SpringBootApplication 来标注一个主程序类,说明这是一个SpringBoot应用
@SpringBootApplication
public class HellowordQuickStartApplication {
public static void main(String[] args) {
/*SpringBoot应用启动项
HellowordQuickStartApplication.class 参数必须是用@SpringBootApplication注解修饰的类
*/
SpringApplication.run(HellowordQuickStartApplication.class, args);
}
}
@SpringBootApplication
(主要由:@SpringBootConfiguration/@EnableAutoConfiguration/@ComponentScan
组成)
@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 {
@SpringBootConfiguration
:标注在某个类上,表示此类是一个SpringBoot
的配置类。由以下注解组合形成:配置类 == 配置文件,配置类也是容器的一个组件,底层由@Component
等等组成。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration //表示此类是一个配置类 是spring的一个组件
public @interface SpringBootConfiguration {
@EnableAutoConfiguration
:开启自动配置功能。也是一个组合注解,由以下注解组成(部分重要注解):
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage
:自动依赖相关的配置包,也是一个组合注解,主要由@import
等注解组合
@Import({Registrar.class})//给容器中导入一个组件;导入的组件由此组建决定。
public @interface AutoConfigurationPackage {
进入@Import(Registrar.class)
中的Registrar
类中,通过断点,可以查看到我注释的一些信息。
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
//registerBeanDefinitions方法中的metadata可以查看到我们启动类使用的注解 @SpringBootApplication
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, new String[]{(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()});
}
//new AutoConfigurationPackages.PackageImport(metadata) 可以解析出我们当前主启动所在的package包
public SetObject> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}
@Import(Registrar.class)
作用:将主配置类的所在包以及下边所有子包里面的所有组件扫描到Spring
容器中。这也就能理解为什么会自动扫描我们写的@Controller
类了。
@Import(AutoConfigurationImportSelector.class)
:进入AutoConfigurationImportSelector.class
类中,查看如下方法:
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if(!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
try {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// 主要用到的是 这个 configurations 后面会有重点说明
ListString> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
configurations = this.sort(configurations, autoConfigurationMetadata);
SetString> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
} catch (IOException var6) {
throw new IllegalStateException(var6);
}
}
}
这是导入组件的选择器方法,将所有需要导入的组件以全类名的方式返回,这些组件最终被添加到容器中。其中List configurations
会给容器中导入非常多的自动配置类[xxxAutoConfiguration
],就是给容器中导入这个场景需要的所有组件,并配置好这些组件。有了自动配置类,免去了我们手动编写配置注入功能组件等的工作;自动配置类共109个,如下部分所示:
☹ 那么我们就有疑问,这些自动配置类都是从哪里来的?
进入这个方法:this.getCandidateConfigurations(annotationMetadata, attributes)
protected ListString> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// *** 后边需要了解的方法 ***
//SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader);
ListString> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
进入SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader)
方法,具体注释说明:
public static ListString> loadFactoryNames(Class?> factoryClass, @Nullable ClassLoader classLoader) {
//org.springframework.context.ApplicationContextInitializer
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static MapString, ListString>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMapString, String> result = (MultiValueMap)cache.get(classLoader);
if(result != null) {
return result;
} else {
try {
//通过类加载器(classLoader获取)META-INF/spring.factories(也就是配置了109个自动配置类的文件) 资源
EnumerationURL> urls = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
//将urls 当做一个properties配置文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry?, ?> entry = (Entry)var6.next();
//将META-INF/spring.factories文件中的EnableAutoConfiguration下的配置进行加载 如下图所示
ListString> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
result.addAll((String)entry.getKey(), factoryClassNames);
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var9) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
}
}
}
我们进入其中一个自动配置类中看看SpringBoot
是不是真的帮我们已经配置好了一些属性[WebMvcAutoConfiguration
]:
//这里我就摘出一些重要的配置,来帮我我们观察即可。
@Configuration
public class WebMvcAutoConfiguration {
@Bean
@ConditionalOnMissingBean
/** 视图解析器 , SpringBoot中的所有配置文件都是.java形式,方法的名字,就是以前xml中的id。
等等都是用注解表示的,这个我们后面会重点说明,这里就先了解一下*/
//我们可以看到SpringBoot已经帮我们配置好了视图解析器 等等一些功能 我们直接使用就好
public InternalResourceViewResolver defaultViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix(this.mvcProperties.getView().getPrefix());
resolver.setSuffix(this.mvcProperties.getView().getSuffix());
return resolver;
}
}
总结: SpringBoot
在启动的时候从类路径下的META-INF/spring.factories
中获取EnableAutoConfiguration
指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。如此一来,就具有我们在SSM
等环境下写了一大堆配置文件后才具有的功能。而这些所有配置文件都在spring-boot-autoconfigure-2.0.0.RELEASE.jar
中。
五、使用 Spring Initializer 快速创建 Spring Boot 项目
注意:Artifact
中不能大小写混合使用。
通过需求选择starts
,例如选择Web
。
我们就会发现pom.xml
文件中,就会自动配置了我们引入的starts
。
parent>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-starter-parentartifactId>
version>2.0.0.RELEASEversion>
relativePath/>
parent>
properties>
project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
java.version>1.8java.version>
properties>
dependencies>
dependency>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-starter-webartifactId>
dependency>
dependency>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-starter-testartifactId>
scope>testscope>
dependency>
dependency>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-configuration-processorartifactId>
optional>trueoptional>
dependency>
dependencies>
添加controller
层: 新注解@RestController == @ResponseBody
与@Controller
的合体;
//这个类的所有方法返回的数据直接写给浏览器(如果是对象转为JSON)
//@ResponseBody@Controller
@RestController
public class HelloWordController {
@RequestMapping("/hello")
public String hello(){
return "hell";
}
}
优点: 默认生成的SpringBoot
项目,我们只需要编写自己的逻辑。默认生成的Resources
配置文件的目录结构:
【1】static
:保存所有的静态资源。 [js/css/image
]
【2】templates
:保存所有的模板页面[SpringBoot
默认jar
包使用嵌入式的 Tomcat
,默认不支持JSP
页面]但可以使用模板引擎。(freemarker
、thymeleaf
)
【3】application.properties
:SpringBoot
应用的配置文件。默认的配置都在此文件可以修改。