为什么学Spring Boot
- 因为j2EE配置太多,开发效率低,复杂的部署流程,第三方技术集成难度大。
- 所以在Spring4.0以后开发出一套框架->Spring Boot.
- Spring Boot简化了Spring应用开发,它规定约定大于配置,just run 就能创建一个独立的、产品级别的应用。
- 阴阳怪气话:哎呀,Spring Boot这么好,我们别学Spring了直接开搞Spring Boot吧。别忘了Spring Boot是继承了Spring的优良传统的[狗头]
环境配置(个人配置)
JDK:javac 1.8.0_144
MAVEN:Apache Maven 3.6.3
开发环境:IntelliJ IDEA 2019.3.3
Spring Boot:2.3.3
Hello World(任何开发必学哈哈哈)
一、 创建maven工程
二、导入Spring Boot相关依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
</parent>
<groupId>com.newbie</groupId>
<artifactId>spring-boot-01-helloworld</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
三、编写主程序,启动Spring Boot应用
package com.newbie;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
**/
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args){
/**
* Spring应用的run方法,顾名思义是让Spring应用跑起来的方法
* 所需参数:要跑起来的主程序类的字节码 .class文件以及传进来的参数
**/
SpringApplication.run(HelloWorldMainApplication.class,args);
}
}
四、编写Controller、Service层
package com.newbie.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloWorldController {
@RequestMapping("/hello")
@ResponseBody
public String Hello(){
return "Hello World!";
}
}
五、张宇式点火
看到这个标志就知道启动成功了,如果想换这个图标可以参考下面链接
更换启动日志输出
六、简化部署
pom文件中加上插件,可在这里找到
<!--可以将应用打包成一个可执行的jar包-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
然后再maven中打包,打包后在target目录下将jar复制出来
win+R cmd
cd到jar包所在目录,输入java - jar spring-boot-01-helloworld-1.0-SNAPSHOT.jar
,即可
七、Hello World分析
1.pom文件
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
</parent>
<!--spring-boot-starter-parent父项目是-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.3.RELEASE</version>
</parent>
<!--这个是真正管理Spring Boot所有依赖的版本,在properties中
Spring Boot的版本仲裁中心,以后导入依赖默认不需要写版本号-->
2.启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
spring-boot-starter-web:
- spring-boot-starter:spring-boot场景启动器;帮我们导入了web应用所需的所有组件;
- Spring Boot 将很多开发所需的场景都包装在starts里了
3.主程序类
package com.newbie;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
1. @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
**/
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args){
/**
* Spring应用的run方法,顾名思义是让Spring应用跑起来的方法
* 所需参数:要跑起来的主程序类的字节码 .class文件以及传进来的参数
**/
SpringApplication.run(HelloWorldMainApplication.class,args);
}
}
@SpringBootApplication:springboot应用,表明这个类是SpringBoot的主配置类
@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配置,表明这是一个Spring Boot的配置类
- @Configuration:配置类上标注这个注解,配置类相当于原来的配置文件;
- @Component:配置类也是容器中的一个组件; -
@EnableAutoConfiguration:开启自动配置功能;这里就是Spring Boot帮我们配置的重点;就是她将Spring原本繁琐的配置给予简化
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
@AutoConfigurationPackage:自动配置包;@Import({Registrar.class});Spring的底层@import,给容器导入一个组件;导入的组件在Registrar.class中;
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
/**
*(String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0])
计算得出下图
**/
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
}
}
@Import({Registrar.class});将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器里
@Import({AutoConfigurationImportSelector.class})
给容器导入那些组件?
AutoConfigurationImportSelector:导入哪些组件的选择器;将所有需要导入的组件以全类名的方式返回;然后被添加到容器中;
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件;
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,ClassLoader);
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> 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);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
getAutoConfigurationEntry–>getCandidateConfigurations–>loadFactoryNames–>loadSpringFactories–>(“META-INF/spring.factories”)
其实就是Spring Boot 在启动时从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作;
J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-2.3.3.RELEASE.jar
八、快速创建Spring Boot项目
使用Spring Initializer