springboot核心技术与响应式编程一
一. 基础入门
1.相关资料
原文档地址 https://www.yuque.com/atguigu/springboot
2.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技术栈快速开发脚手架
二.时代背景
1.微服务
- 微服务是一种架构风格
一个应用拆分为一组小型服务
每个服务运行在自己的进程内,也就是可独立部署和升级
服务之间使用轻量级HTTP交互
服务围绕业务功能拆分
可以由全自动部署机制独立部署
去中心化,服务自治。服务可以使用不同的语言、不同的存储技术
2. 分布式
1. 分布式困难
- 远程调用
服务发现
负载均衡
服务容错
配置管理
服务监控
链路追踪
日志管理
任务调度
2. 分布式解决
- SpringBoot + SpringCloud
3. 云原生
三. helloword入门
1. maven配置
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
2. 简化部署--打包配置
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
3. 自动配置原理
1.自动配置tomcat
自动引入了tomcat依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.5.1</version>
<scope>compile</scope>
</dependency>
自动配置tomcat
自动配置springMVC
引入springMVC的全套组件
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.8</version>
<scope>compile</scope>
</dependency>
自动配置好springMVC的常用组件
自动配置web
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.8</version>
<scope>compile</scope>
</dependency>
默认包结构
主程序所在的包及其下面的所有子包里面的组件都会被扫描
其他的包可以在启动类上添加scanBasePackages
@SpringBootApplication(scanBasePackages = {""})
添加包扫码结构
@ComponentScan("com.wu")
各种配置拥有默认值
默认的配置,最终都是映射到某一个类上
配置文件的值,最终会绑定在每个类上,这个类会在容器中创建对象
按需加载所有自动配置项
非常多的starter
引入了哪些场景,该场景的配置才会开启
springboot所有的自动配置功能都在autoconfigure场景下
四. 核心注解
1.@Configuration
告诉springboot这是一个配置类,等于以前的配置文件
package com.wu.springboot.config;
import com.wu.springboot.pojo.Pet;
import com.wu.springboot.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 1.在配置类里面使用@Bean注解在方法上,给容器添加组件。这些组件都是单例模式。当组件有对象参数传递时,会在当前容器中查询是否存在当前类型的组件。然后使用查询到的组件作为参数传递
* 2. 配置类本身也是组件
* 3. proxyBeanMethods 代理实例方法
* full(proxyBeanMethods = true) 全代理 springboot在启动的时候,会检查每个组件的实例是否存在
* lite(proxyBeanMethods = false)轻量代理 springboot 在启动的时候,不会检查每个组件的实例(跳过检查。
* 在其他地方使用对象调用方法时,生成的实例也不是单例
* 组件依赖
* 如果只是在容器中注册组件,其他地方对其没有依赖。修改为false,能提升springboot的启动速度
*/
@Configuration(proxyBeanMethods = true) //告诉springboot,这是一个配置类,相当于之前的配置文件
public class MyConfigruation {
@Bean //给容器添加组件,以方法名作为组件的id。返回类型就是组件类型, 返回的值就是组件在容器中的实例
public User userO1(){
return new User("张三",20);
}
@Bean("tom01") //可以不使用方法名作为组件的id。在Bean注解内自定义组件id
public Pet tom(){
return new Pet("tom",2);
}
}
package com.wu.springboot;
import com.wu.springboot.config.MyConfigruation;
import com.wu.springboot.pojo.Pet;
import com.wu.springboot.pojo.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
//ComponentScan已经在SpringBootApplication有了。默认扫描的是当前类所在的包
@ComponentScan("com.wu")
@SpringBootApplication
public class SpringbootMain {
public static void main(String[] args) {
//返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(SpringbootMain.class, args);
//配置类也是一个实例
MyConfigruation myConfigruation = run.getBean("myConfigruation", MyConfigruation.class);
System.out.println(myConfigruation);
//从容器中获取user和pet的实例,对比调用对象方法生成实例
User userO1 = run.getBean("userO1", User.class);
Pet tom01 = run.getBean("tom01", Pet.class);
Pet tom = myConfigruation.tom();
User user = myConfigruation.userO1();
System.out.println(tom01==tom); //1配置配代理方法为true时@Configuration(proxyBeanMethods = true) 为true proxyBeanMethods = false-->false
System.out.println(userO1==user);//1配置配代理方法为true时@Configuration(proxyBeanMethods = true) 为true proxyBeanMethods = false-->false
}
}
2. @import注解
导入注解
* 4.Import注解
* 在容器中自动创建对应类型的组件。默认组件名字就是全类名
* 如@Import({DBHelper.class, JNDIConnectionSource.class})
* 会自动创建DBHelper和JNDIConnectionSource的实例
打印容器内的实例
for (String name :run.getBeanDefinitionNames()){
System.out.println(name);
}
输出中包含
ch.qos.logback.core.db.DBHelper
ch.qos.logback.core.db.JNDIConnectionSource
3.@Conditional 注解
条件装配,满足对应的条件,则进行组件注入
@ConditionalOnBean(name = "tom01")//条件装配,当存在实例tom01的时候,才装配该组件
@ConditionalOnMissingBean(name = "tomm") //条件装配,当容器中不存在tomm实例时,才装配该组件
用在配置类上面,则作用于整个配置类下面的组件
如果用在方法上,只作用于当前方法
注意:实例在生成的时候有先后顺序!!!
4. @ImportResource 导入原生的资源配置文件
@ImportResource("classpath:beans.xml")//导入原生的资源配置文件
5. 配置绑定
组件注入时,使用配置文件中对应的属性值
yml中配置
#自定义配置
car.carName: BYD
car.price: 10000
实例配置
@Data
@Component//将该类注册到IOC容器中。只有容器中的组件,才能使用springboot提供的相关功能
@ConfigurationProperties(prefix="car") //使用配置文件中,前缀和car匹配的值.
public class Car {
private String carName;
private String price;
}
使用(自动注入使用):
@Resource
private Car car;
另一种配置方式,在配置文件中使用
@EnableConfigurationProperties(Car.class) //开启car类的属性配置功能。将car组件添加到容器中
五. 自动配置原理
SpringBootApplication包含注解分析
1.@SpringBootConfiguration
主要注解Configuration 代表该类是一个配置文件
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}
2. @ComponentScan
组件扫描
3. @EnableAutoConfiguration
自动配置包,指定了默认的包规则
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
1. @AutoConfigurationPackage
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
@Import 导入对应的组件
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}
register()将该包下的所有组件导入到IOC容器中
new PackageImports(metadata).getPackageNames()获取到的包名时Main方法所的包。侧面印证了springboot在启动的时候,只有Main方法所在包及子包下的组件才会生效的原因
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
if (registry.containsBeanDefinition(BEAN)) {
BasePackagesBeanDefinition beanDefinition = (BasePackagesBeanDefinition) registry.getBeanDefinition(BEAN);
beanDefinition.addBasePackages(packageNames);
}
else {
registry.registerBeanDefinition(BEAN, new BasePackagesBeanDefinition(packageNames));
}
}
2. @Import(AutoConfigurationImportSelector.class)
先获取所有的组件配置信息,再通过各种条件注入动态的注入组件
@Import(AutoConfigurationImportSelector.class)//利用该方法给容器导入组件
引用流程链
- selectImports方法 查询导入的配置
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
getAutoConfigurationEntry() 获取自动配置的组件
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); }
getCandidateConfigurations(annotationMetadata, attributes) 获取所有配置组件信息
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;
}
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader()); 使用工厂加载器加载
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()); }
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 { 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; }
Enumeration
urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION); 从配置文件中获取对应的加载信息 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
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.context.ConfigurationPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\ org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\ org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\ org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\ ...........
六.最佳实践
引入场景依赖。springboot列举了所有第三方配置的依赖
查看自动配置了哪些
配置文件中使用debug=true
是否需要配置项
自己分析xxxproperties绑定了哪些内容
自定义加入或替换组件
自定义器 xxxCustomizer
七.开发小技巧
1. lombok
2. dev-tools
热更新
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
3. spring initailizr
- 本文标签: Spring Boot Java
- 本文链接: https://www.tianyajuanke.top/article/36
- 版权声明: 本文由吴沛芙原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权