1. SpringBoot概述

1.1 springboot简介

springboot之所以能使用广泛也基于微服务分布式的的崛起。

1.2 SpringBoot特点

1.SpringBoot优点
• Create stand-alone Spring applications
• 创建独立Spring应用
• Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
• 内嵌web服务器
• Provide opinionated ‘starter’ dependencies to simplify your build configuration
• 自动starter依赖,简化构建配置
• Automatically configure Spring and 3rd party libraries whenever possible
• 自动配置Spring以及第三方功能
• Provide production-ready features such as metrics, health checks, and externalized configuration
• 提供生产级别的监控、健康检查及外部化配置
• Absolutely no code generation and no requirement for XML configuration
• 无代码生成、无需编写XML
SpringBoot是整合Spring技术栈的一站式框架
SpringBoot是简化Spring技术栈的快速开发脚手架

2.SpringBoot缺点
• 人称版本帝,迭代快,需要时刻关注变化
• 封装太深,内部原理复杂,不容易精通

1.3 Spring官网说明

在这里插入图片描述
官网文档架构在这里插入图片描述在这里插入图片描述查看版本新特性;
https://github.com/spring-projects/spring-boot/wiki#release-notes
在这里插入图片描述

2. SpringBoot案例

入门案例参照官方文档:https://docs.spring.io/spring-boot/docs/current/reference/html/index.html

上文官网文档架构中的入门对应连接Getting Started。
在这里插入图片描述

2.1 系统要求

1.1、maven设置

2.2 创建项目

2.3 引入依赖

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>myproject</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.1</version>
    </parent>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>

2.4 创建测试

在这里插入图片描述

import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.web.bind.annotation.*;

@RestController
@EnableAutoConfiguration
public class Example {

    @RequestMapping("/")
    String home() {
        return "Hello World!";
    }

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

}

2.5 测试验证

访问浏览器地址:http://localhost:8080/
返回:hello world!
在这里插入图片描述

3. SpringBoot特点

3.1 依赖管理

  • 父项目做依赖管理
依赖管理    
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
</parent>

他的父项目
 <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.3.4.RELEASE</version>
  </parent>

几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制

3.2 场景启动器

1、见到很多 spring-boot-starter-* : *就某种场景
2、只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
3、SpringBoot所有支持的场景
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
4、见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
5、所有场景启动器最底层的依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
  <version>2.3.4.RELEASE</version>
  <scope>compile</scope>
</dependency>

3.3 自动版本仲裁

无需关注版本号,自动版本仲裁
1、引入依赖默认都可以不写版本
2、引入非版本仲裁的jar,要写版本号。

3.可以修改默认版本号。

1、查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。
2、在当前项目里面重写配置
    <properties>
        <mysql.version>5.1.43</mysql.version>
    </properties>

4.自动配置

• 自动配好Tomcat
• 自动配好SpringMVC
		• 引入SpringMVC全套组件
		• 自动配好SpringMVC常用组件(功能)
• 自动配好Web常见功能,如:字符编码问题
		• SpringBoot帮我们配置好了所有web开发的常见场景
• 默认的包结构
		• 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
		• 无需以前的包扫描配置
		• 想要改变扫描路径,@SpringBootApplication(scanBasePackages="com")
		• 或者@ComponentScan 指定扫描路径
		
		@SpringBootApplication
		等同于
		@SpringBootConfiguration
		@EnableAutoConfiguration
		@ComponentScan("com.atguigu.boot")

• 各种配置拥有默认值
		• 默认配置最终都是映射到某个类上,如:MultipartProperties
		• 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
• 按需加载所有自动配置项
		• 非常多的starter
		• 引入了哪些场景这个场景的自动配置才会开启
		• SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
。。。

4. SpringBoot容器功能

2.1、组件添加
1、@Configuration

@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
 2、配置类本身也是组件
 3、proxyBeanMethods:代理bean的方法
      Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
      Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】
      组件依赖必须使用Full模式默认。其他默认是否Lite模式

2、@Bean、@Component、@Controller、@Service、@Repository

定义一些组件

3、@ComponentScan、@Import

@ComponentScan("com.hey.boot")
指定包扫描路径

@Import({User.class, DBHelper.class})
 给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名

4、@Conditional

条件装配:满足Conditional指定的条件,则进行组件注入

在这里插入图片描述
2.2、原生配置文件引入
1、@ImportResource

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:context="http://www.springframework.org/schema/context"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <bean id="haha" class="com.atguigu.boot.bean.User">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="18"></property>
    </bean>
    <bean id="hehe" class="com.atguigu.boot.bean.Pet">
        <property name="name" value="tomcat"></property>
    </bean>
</beans>
// xml配置bean以后,通过注解@ImportResource("classpath:beans.xml")放到容器中。
@ImportResource("classpath:beans.xml")
public class MyConfig {
public static void main(String[] args) {
        //1、返回我们IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
         boolean haha = run.containsBean("haha");
        boolean hehe = run.containsBean("hehe");
        System.out.println("haha:"+haha);//true
        System.out.println("hehe:"+hehe);//true
        }
}

2.3、配置绑定
1、@ConfigurationProperties

/**
 * 只有在容器中的组件,才会拥有SpringBoot提供的强大功能
 */
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {}

2、@EnableConfigurationProperties + @ConfigurationProperties
3、@Component + @ConfigurationProperties

@EnableConfigurationProperties(Car.class)
//1、开启Car配置绑定功能
//2、把这个Car这个组件自动注册到容器中
public class MyConfig {
}

5. SpringBoot配置原理

5.1 自动配置流程

首先是主启动类注解@SpringBootApplication,这是一个组合注解,其中有两个比较重要的注解@SpringBootConfiguration
@EnableAutoConfiguration

@SpringBootConfiguration注解是一个配置注解@Configuration,其本质也是一个spring组件@Component。

@EnableAutoConfiguration注解有两个比较重要的注解:
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)

@AutoConfigurationPackage注解下有一个注解@Import(AutoConfigurationPackages.Registrar.class),springboot注册器,Registrar注册器通过registerBeanDefinitions方法获取包扫描路径。

springboot选择器AutoConfigurationImportSelector.class是springboot自动配置的核心类。AutoConfigurationImportSelector类通过getAutoConfigurationEntry方法中getCandidateConfigurations方法获取META-INF/spring.factories中已经配置好的xxxAutoConfiguration配置,根据@ConditionalOnMissingBean与@ConditionalOn判断加载指定的配置,判断条件一般指jar包是否引入,而不是全部加载spring.properties中的配置。

5.2 自动配置源码分析

主启动类注解

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

}

引导加载自动配置类

@SpringBootConfiguration
@EnableAutoConfiguration
public @interface SpringBootApplication {}   

@SpringBootConfiguration
本质是一个@Configuration。代表当前是一个配置类,本质是@Component,是spring组件。

@Configuration
public @interface SpringBootConfiguration {}

@Component
public @interface Configuration {}

@EnableAutoConfiguration

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

@AutoConfigurationPackage
springBoot注册器Registrar,获取扫描路径。

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}

@Import(AutoConfigurationImportSelector.class)
自动配置选择器,选择注入配置的信息

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		// 获取配置信息
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		// 返回字符串数组
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

	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);
	}

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
	// 加载配置信息
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				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;
	}

	// 具体加载方法
	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		ClassLoader classLoaderToUse = classLoader;
		if (classLoaderToUse == null) {
			classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
		}
		String factoryTypeName = factoryType.getName();
		return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
	}

	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
		Map<String, List<String>> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		result = new HashMap<>();
		try {
		// 具体加载路径FACTORIES_RESOURCE_LOCATION:
		// public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					String[] factoryImplementationNames =
							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
					for (String factoryImplementationName : factoryImplementationNames) {
						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
								.add(factoryImplementationName.trim());
					}
				}
			}

			// Replace all lists with unmodifiable lists containing unique elements
			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
			cache.put(classLoader, result);
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
		return result;
	}

虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
按照条件装配规则(@Conditional),最终会按需配置。

3.3、修改默认配置
```java
@Bean
@ConditionalOnBean(MultipartResolver.class)  //容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
		public MultipartResolver multipartResolver(MultipartResolver resolver) {
//给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
//SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
// Detect if the user has created a MultipartResolver but named it incorrectly
			return resolver;
}
给容器中加入了文件上传解析器;

总结:
• SpringBoot先加载所有的自动配置类  xxxxxAutoConfiguration
• 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
• 生效的配置类就会给容器中装配很多组件
• 只要容器中有这些组件,相当于这些功能就有了
• 定制化配置
• 用户直接自己@Bean替换底层的组件
• 用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration ---> 组件  ---> xxxxProperties里面拿值  ----> application.properties

3.4、最佳实践

• 引入场景依赖
• https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
• 查看自动配置了哪些(选做)
• 自己分析,引入场景对应的自动配置一般都生效了
• 配置文件中debug=true开启自动配置报告。Negative(不生效)\Positive(生效)
• 是否需要修改
• 参照文档修改配置项
• https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties
• 自己分析。xxxxProperties绑定了配置文件的哪些。
• 自定义加入或者替换组件
• @Bean、@Component。。。
• 自定义器  XXXXXCustomizer;
• ......

5.3 开发技巧

4.1、Lombok

1、引入依赖
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>


2、idea中搜索安装lombok插件

3、常用注解
@NoArgsConstructor
@AllArgsConstructor
@Data
@ToString
@EqualsAndHashCode
@Slf4j

4.2、dev-tools
这是一个假的热部署,项目或者页面修改以后:Ctrl+F9;
真正的热部署使用插件rebel。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

4.3、Spring Initailizr(项目初始化向导)
在这里插入图片描述

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐