赞
踩
所有的技术框架的发展似乎都遵循了一条主线规律:
- 从一个复杂应用场景衍生一种规范框架, 人们只需要进行各种配置而不需要自己去实现它, 这时候强大的配置功能成了优点;
- 发展到一定程度之后, 人们根据实际生产应用情况, 选取其中实用功能和设计精华, 重构出一些轻量级的框架;
- 之后为了提高开发效率, 嫌弃原先的各类配置过于麻烦, 于是开始提倡 “约定大于配置″, 进而衍生出一些一站式的解决方案。
这就是 Java 企业级应用 ->J2EE-> spring-> spring boot 的过程。
优点:1. 节省了调用资源。2. 每个功能元素的服务都是一个可替换的、可独立升级的软件代码。
优点:易于开发和测试,方便部署;当需要扩展时,只需要将 war 复制多份, 然后放到多个服务器上, 再做个负载均衡就可以了。
缺点:修改一个非常小的地方, 都需要停掉整个服务, 重新打包部署这个应用 War 包;对于一个大型应用,如何维护,如何分工合作都是问题。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
自动导包的核心 AutoConfigurationImportSelector 类:选择了什么东西
AutoConfigurationImportSelector 类中的方法:
// 1.获得自动配置实体(调用“获取所有候选配置”的方法获取实体)。 protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) // 2.获取所有候选配置(候选配置是哪些配置)。 List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes){ List<String> 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; } // 3.候选配置是所有标注@EnableAutoConfiguration注解的类下的所有配置。(即获取主启动类下的所有配置) protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; } // 4.获取所有的配置从哪里来,上面第二个方法调用了loadFactoryNames方法 public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); } // 5.loadFactoryNames方法调用了loadSpringFactories方法 // 6.loadSpringFactories方法从项目资源和系统资源中获取配置文件 classLoader.getResources("META-INF/spring.factories") ClassLoader.getSystemResources("META-INF/spring.factories")
META-INF/spring.factories:自动配置的核心文件。
// 遍历所有的资源,封装成properties供我们使用
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
结论: springboot 所有自动配置都是在启动的时候扫描并加载: 所有的自动配置类都在 spring.factories 里面,但是不一定生效;要判断条件是否成立:只要导入了对应的 start,就有对应的启动器,有了启动器,我们自动装配就会生效,然后自动配置就可以成功。
详细步骤:
main 方法中的 run 方法启动会开启一个服务。
@SpringBootApplication
public class SpringbootWeb01Application {
public static void main(String[] args) {
// 该方法返回一个ConfigurableApplicationContext对象
// 参数一:应用入口的类, 参数二:命令行参数
SpringApplication.run(SpringbootWeb01Application.class, args);
}
}
主要两部分
springboot 配置文件能够配置的东西都有一个固有的规律:
他们都有对应的 xxxAutoConfiguration 配置类,这个配置类都会绑定一个 xxxProperties 类,xxxProperties 类和 springboot 的配置文件绑定;这样我们就可以在 springboot 配置文件中自定义配置了。
spring 的底层注解:根据不同的条件,来判断当前配置或者类是否生效。@Conditionalxxx
SpringBoot 使用一个全局的配置文件,配置文件名是固定的。
全局配置文件的作用:修改 SpringBoot 自动配置的默认值,它会在底层帮我们自动配置。
# 对象
student:
name: 'zs'
age: 12
# 对象的行内写法
student1: {
name: 'zs',age: 12}
# 数组
pets:
- cat
- dog
- pig
# 数组行内写法
pets1: [cat,dog,pig]
/* ConfigurationProperties作用 将yml配置文件中配置的每个属性的值,映射到这个组件中; 告诉SpringBoot将本类中的所有属性和yml配置文件中相关的配置进行绑定; 参数prefix="person":将yml配置文件中的person下面的所有属性和本类属性对应。 (只有这个组件是容器中的组件,才能使用容器提供的ConfigurationProperties功能) */ // 可以直接拿到复杂类型的值 @Component @ConfigurationProperties(prefix = "person") @Data public class Person { private String name; private Integer age; private Boolean flag; private Date birth; private Map<String,Object> map; private List<Object> list; private Dog dog; }
// application.yml
person:
name: zs
age: 12
flag: false
birth: 2021/04/20
map: {
k1: v1,k2: v2}
list: [code,music,girl]
dog:
name: 旺财
age: 3
<!--spring-boot-configuration-processor依赖可以在yml配置时给出提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
// 复杂类型不能用@Value直接取值 @Configuration @Data public class Person { @Value("${person222.name}") private String name; @Value("${person222.age}") private Integer age; @Value("${person222.flag}") private Boolean flag; @Value("${person222.birth}") private Date birth; private Map<String,Object> map; private List<Object> list; private Dog dog; }
// application.yml
person222:
name: zs
age: 12
flag: false
birth: 2021/04/20
map: {
k1: v1,k2: v2}
list: [code,music,girl]
dog:
name: 旺财
age: 3
@Component @PropertySource(value = "classpath:test.properties")//可以这样配置@PropertySource({"classpath:test.properties"}) @Data public class Person { // SPEL表达式取出配置文件的值 @Value("${name}") private String name; @Value("${age}") private Integer age; private Boolean flag; private Date birth; private Map<String,Object> map; private List<Object> list; private Dog dog; }
// test.properties
name=zhangsan
age=13
yml 配置属性的 - 可以和实体属性的驼峰对应绑定
@Component
@ConfigurationProperties(prefix = "person")
@Data
public class Person {
private String firstName;
}
// application.yml
person:
first-name: zs
@Component
@ConfigurationProperties(prefix = "person")
@Data
@Validated //数据校验
public class Person {
@Email(message="邮箱格式错误")
private String name;
}
HibernateValidator 是 BeanValidation 的参考实现;HibernateValidator 提供了 JSR 303 规范中所有内置 constraint 的实现;和附加的 constraint
HibernateValidator 附加的 constraint
<!--thymeleaf,我们都是基于3.x开发;2.x项目会报错-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<div th:text="${msg}"></div>
</body>
</html>
package com.sywl.config;
import org.springframework.context.annotation.Configuration;
import org.springframework
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。