一、Spring Boot 入门
1、Spring Boot 简介
简化Spring应用开发的一个框架; 整个Spring技术栈的一个大整合; J2EE开发的一站式解决方案;
2、微服务
2014,martin fowler
微服务:架构风格(服务微化)
一个应用应该是一组小型服务;可以通过HTTP的方式进行互通;
单体应用:ALL IN ONE
微服务:每一个功能元素最终都是一个可独立替换和独立升级的软件单元;
3、环境准备
环境约束
–jdk1.8:Spring Boot 推荐jdk1.7及以上;java version “1.8.0_112”
–maven3.x:maven 3.3以上版本;Apache Maven 3.3.9
–IntelliJIDEA2017:IntelliJ IDEA 2017.2.2 x64、STS
–SpringBoot 1.5.9.RELEASE:1.5.9;
统一环境;
1、MAVEN设置;
给maven 的settings.xml配置文件的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>
2、IDEA设置
整合maven进来;
4、Spring Boot HelloWorld
一个功能:
浏览器发送hello请求,服务器接受请求并处理,响应Hello World字符串;
1、创建一个maven工程;(jar)
2、导入spring boot相关的依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.1</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
3、编写一个主程序;启动Spring Boot应用
/** * 主程序类 * @SpringBootApplication :这是一个SpringBoot应用 */ @SpringBootApplication public class MainApplication { public static void main(String[] args) { //spring应用启动起来 SpringApplication.run(MainApplication.class,args); } }
4、编写相关的Controller、Service
@Controller public class HelloController { @ResponseBody @RequestMapping("/hello") public String handle01(){ return "hello,mdfk!"; } }
5、运行主程序测试
6、简化部署
<!-- 这个插件,可以将应用打包成一个可执行的jar包;--> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
将这个应用打成jar包,直接使用java -jar的命令进行执行;
7、简化配置
server.port=8888
在IDEA的Maven插件上点击运行 clean 、package,把helloworld工程项目的打包成jar包,
打包好的jar包被生成在helloworld工程项目的target文件夹内。
用cmd运行java -jar boot-01-helloworld-1.0-SNAPSHOT.jar,既可以运行helloworld工程项目。
将jar包直接在目标服务器执行即可。
5、依赖管理特性
- 父项目做依赖管理
依赖管理 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.1</version> </parent> 上面项目的父项目如下: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.6.1</version> </parent> 它几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制
- 开发导入starter场景启动器
-
- 见到很多 spring-boot-starter-* : *就某种场景
- 只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
- 更多SpringBoot所有支持的场景
- 见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
所有场景启动器最底层的依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.6.1</version> <scope>compile</scope> </dependency>
- 无需关注版本号,自动版本仲裁
-
- 引入依赖默认都可以不写版本
- 引入非版本仲裁的jar,要写版本号。
- 可以修改默认版本号
-
- 查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。
- 在当前项目里面重写配置,如下面的代码。
<properties> <mysql.version>5.1.43</mysql.version> </properties>
IDEA快捷键:
- ctrl + shift + alt + U:以图的方式显示项目中依赖之间的关系。
- alt + ins:相当于Eclipse的 Ctrl + N,创建新类,新包等。
6、自动配置特性
- 自动配好Tomcat
-
- 引入Tomcat依赖。
- 配置Tomcat
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <version>2.6.1</version> <scope>compile</scope> </dependency>
- 自动配好SpringMVC
-
- 引入SpringMVC全套组件
- 自动配好SpringMVC常用组件(功能)
- 自动配好Web常见功能,如:字符编码问题
-
- SpringBoot帮我们配置好了所有web开发的常见场景
public static void main(String[] args) { //1、返回我们IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); //2、查看容器里面的组件 String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } }
- 默认的包结构
-
- 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
- 无需以前的包扫描配置
- 想要改变扫描路径
-
-
- @SpringBootApplication(scanBasePackages=“com.lun”)
- @ComponentScan 指定扫描路径
-
@SpringBootApplication 等同于 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com.tpac")
- 各种配置拥有默认值
-
- 默认配置最终都是映射到某个类上,如:MultipartProperties
- 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
- 按需加载所有自动配置项
-
- 非常多的starter
- 引入了哪些场景这个场景的自动配置才会开启
- SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
7、底层注解-@Configuration详解
- 基本使用
-
- Full模式与Lite模式
- 示例
/** * 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的 * 2、配置类本身也是组件 * 3、proxyBeanMethods:代理bean的方法 * Full(proxyBeanMethods = true)(保证每个@Bean方法被调用多少次返回的组件都是单实例的)(默认) * Lite(proxyBeanMethods = false)(每个@Bean方法被调用多少次返回的组件都是新创建的) */ @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 public class MyConfig { /** * Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象 * @return */ @Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例 public User user01(){ User zhangsan = new User("zhangsan", 18); //user组件依赖了Pet组件 zhangsan.setPet(tomcatPet()); return zhangsan; } @Bean("tom") public Pet tomcatPet(){ return new Pet("tomcat"); } }
@Configuration测试代码如下:
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com.atguigu.boot") public class MainApplication { public static void main(String[] args) { //1、返回我们IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); //2、查看容器里面的组件 String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } //3、从容器中获取组件 Pet tom01 = run.getBean("tom", Pet.class); Pet tom02 = run.getBean("tom", Pet.class); System.out.println("组件:"+(tom01 == tom02)); //4、com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892 MyConfig bean = run.getBean(MyConfig.class); System.out.println(bean); //如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。 //保持组件单实例 User user = bean.user01(); User user1 = bean.user01(); System.out.println(user == user1); User user01 = run.getBean("user01", User.class); Pet tom = run.getBean("tom", Pet.class); System.out.println("用户的宠物:"+(user01.getPet() == tom)); } }
- 最佳实战
-
- 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
- 配置 类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式(默认)
8、底层注解-@Import导入组件
@Bean、@Component、@Controller、@Service、@Repository,它们是Spring的基本标签,在Spring Boot中并未改变它们原来的功能。
@ComponentScan 在07、基础入门-SpringBoot-自动配置特性有用例。
@Import({User.class, DBHelper.class})给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
@Import({User.class, DBHelper.class}) @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 public class MyConfig { }
测试类:
//1、返回我们IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); //... //5、获取组件 String[] beanNamesForType = run.getBeanNamesForType(User.class); for (String s : beanNamesForType) { System.out.println(s); } DBHelper bean1 = run.getBean(DBHelper.class); System.out.println(bean1);
9、底层注解-@Conditional条件装配
条件装配:满足Conditional指定的条件,则进行组件注入
用@ConditionalOnMissingBean举例说明
@Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(name = "tom")//没有tom名字的Bean时,MyConfig类的Bean才能生效。 public class MyConfig { @Bean public User user01(){ User zhangsan = new User("zhangsan", 18); zhangsan.setPet(tomcatPet()); return zhangsan; } @Bean("tom22") public Pet tomcatPet(){ return new Pet("tomcat"); } } public static void main(String[] args) { //1、返回我们IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); //2、查看容器里面的组件 String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } boolean tom = run.containsBean("tom"); System.out.println("容器中Tom组件:"+tom);//false boolean user01 = run.containsBean("user01"); System.out.println("容器中user01组件:"+user01);//true boolean tom22 = run.containsBean("tom22"); System.out.println("容器中tom22组件:"+tom22);//true }
10、底层注解-@ImportResource导入Spring配置文件
比如,公司使用bean.xml文件生成配置bean,然而你为了省事,想继续复用bean.xml,@ImportResource粉墨登场。
bean.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans ..."> <bean id="haha" class="com.lun.tpac.bean.User"> <property name="name" value="zhangsan"></property> <property name="age" value="18"></property> </bean> <bean id="hehe" class="com.tpac.boot.bean.Pet"> <property name="name" value="tomcat"></property> </bean> </beans>
使用方法:
@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 }
11、底层注解-@ConfigurationProperties配置绑定
如何使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用
传统方法:
public class getProperties { public static void main(String[] args) throws FileNotFoundException, IOException { Properties pps = new Properties(); pps.load(new FileInputStream("a.properties")); Enumeration enum1 = pps.propertyNames();//得到配置文件的名字 while(enum1.hasMoreElements()) { String strKey = (String) enum1.nextElement(); String strValue = pps.getProperty(strKey); System.out.println(strKey + "=" + strValue); //封装到JavaBean。 } } }
Spring Boot一种配置配置绑定:
@ConfigurationProperties + @Component
假设有配置文件application.properties
mycar.brand=BYD mycar.price=100000
只有在容器中的组件,才会拥有SpringBoot提供的强大功能
@Component @ConfigurationProperties(prefix = "mycar") public class Car { ... }
Spring Boot另一种配置配置绑定:
@EnableConfigurationProperties + @ConfigurationProperties
-
- 开启Car配置绑定功能
- 把这个Car这个组件自动注册到容器中
@EnableConfigurationProperties(Car.class) public class MyConfig { ... }
@ConfigurationProperties(prefix = "mycar") public class Car { ... }
12、自动配置【源码分析】-自动包规则原理
Spring Boot应用的启动类:
@SpringBootApplication public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } }
分析下@SpringBootApplication
@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,@EnableAutoConfiguration,@ComponentScan。
@SpringBootConfiguration
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { @AliasFor( annotation = Configuration.class ) boolean proxyBeanMethods() default true; }
@Configuration代表当前是一个配置类。
@ComponentScan
指定扫描哪些Spring注解。
@ComponentScan 在6、自动配置特性有用例。
@EnableAutoConfiguration
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
重点分析@AutoConfigurationPackage,@Import(AutoConfigurationImportSelector.class)。
@AutoConfigurationPackage
标签名直译为:自动配置包,指定了默认的包规则。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class)//给容器中导入一个组件 public @interface AutoConfigurationPackage { String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; }
- 利用Registrar给容器中导入一系列组件
- 将指定的一个包下的所有组件导入进MainApplication所在包下。
13、自动配置【源码分析】-初始加载自动配置类
@Import(AutoConfigurationImportSelector.class)
- 利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
- 调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
- 利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
- 从META-INF/spring.factories位置来加载一个文件。
- 默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
- spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
# 文件里面写死了spring-boot一启动就要给容器中加载的所有配置类 # spring-boot-autoconfigure-2.3.4.RELEASE.jar/META-INF/spring.factories # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ ...
虽然我们127个场景的所有自动配置启动的时候默认全部加载,但是xxxxAutoConfiguration按照条件装配规则(@Conditional),最终会按需配置。
如AopAutoConfiguration类:
@Configuration( proxyBeanMethods = false ) @ConditionalOnProperty( prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true ) public class AopAutoConfiguration { public AopAutoConfiguration() { } ... }
14、自动配置【源码分析】-自动配置流程
以DispatcherServletAutoConfiguration的内部类DispatcherServletConfiguration为例子:
@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默认会在底层配好所有的组件,但是如果用户自己配置了以用户的优先。
总结:
-
- SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
- 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。(xxxxProperties里面读取,xxxProperties和配置文件进行了绑定)
- 生效的配置类就会给容器中装配很多组件
- 只要容器中有这些组件,相当于这些功能就有了
- 定制化配置
-
-
- 用户直接自己@Bean替换底层的组件
- 用户去看这个组件是获取的配置文件什么值就去修改。(修改配置文件就行了,详见官网配置文件参数)
-
xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 ----> application.properties
15、最佳实践-Lombok简化开发
Lombok用标签方式代替构造器、getter/setter、toString()等鸡肋代码。
spring boot已经管理Lombok。引入依赖:
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
IDEA中File->Settings->Plugins,搜索安装Lombok插件。
@NoArgsConstructor //@AllArgsConstructor @Data @ToString @EqualsAndHashCode public class User { private String name; private Integer age; private Pet pet; public User(String name,Integer age){ this.name = name; this.age = age; } }
简化日志开发
@Slf4j @RestController public class HelloController { @RequestMapping("/hello") public String handle01(@RequestParam("name") String name){ log.info("请求进来了...."); return "Hello, Spring Boot 2!"+"你好:"+name; } }
16、最佳实践-dev-tools
添加依赖:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> </dependencies>
在IDEA中,项目或者页面修改以后:Ctrl+F9。
17、最佳实践-Spring Initailizr
Spring Initailizr是创建Spring Boot工程向导。
在IDEA中,菜单栏New -> Project -> Spring Initailizr。
18、配置文件-yaml的用法
同以前的properties用法
YAML 是 “YAML Ain’t Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。
非常适合用来做以数据为中心的配置文件。.
基本语法
- key: value;kv之间有空格
- 大小写敏感
- 使用缩进表示层级关系
- 缩进不允许使用tab,只允许空格
- 缩进的空格数不重要,只要相同层级的元素左对齐即可
- '#'表示注释
- 字符串无需加引号,如果要加,单引号’’、双引号""表示字符串内容会被 转义、不转义
数据类型
- 字面量:单个的、不可再分的值。date、boolean、string、number、null
k: v
- 对象:键值对的集合。map、hash、set、object
#行内写法: k: {k1:v1,k2:v2,k3:v3} #或 k: k1: v1 k2: v2 k3: v3
- 数组:一组按次序排列的值。array、list、queue
#行内写法: k: [v1,v2,v3] #或者 k: - v1 - v2 - v3
实例
@Data public class Person { private String userName; private Boolean boss; private Date birth; private Integer age; private Pet pet; private String[] interests; private List<String> animal; private Map<String, Object> score; private Set<Double> salarys; private Map<String, List<Pet>> allPets; } @Data public class Pet { private String name; private Double weight; }
用yaml表示以上对象
person: userName: zhangsan boss: false birth: 2019/12/12 20:12:33 age: 18 pet: name: tomcat weight: 23.4 interests: [篮球,游泳] animal: - jerry - mario score: english: first: 30 second: 40 third: 50 math: [131,140,148] chinese: {first: 128,second: 136} salarys: [3999,4999.98,5999.99] allPets: sick: - {name: tom} - {name: jerry,weight: 47} health: [{name: mario,weight: 47}]
19、配置文件-自定义类绑定的配置提示
自定义的类和配置文件绑定一般没有提示。若要提示,添加如下依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <!-- 下面插件作用是工程打包时,不将spring-boot-configuration-processor打进包内,让其只在编码的时候有用 --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build>
20、web场景-web开发简介
21、web场景-静态资源规则与定制化
静态资源目录
只要静态资源放在类路径下: called /static (or /public or /resources or /META-INF/resources
访问 : 当前项目根路径/ + 静态资源名
原理: 静态映射/**。
请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404页面。
也可以改变默认的静态资源路径,/static,/public,/resources, /META-INF/resources失效
resources: static-locations: [classpath:/haha/]
静态资源访问前缀
spring: mvc: static-path-pattern: /res/**
当前项目 + static-path-pattern + 静态资源名 = 静态资源文件夹下找
webjar
可用jar方式添加css,js等资源文件,
WebJars - Web Libraries in Jars
例如,添加jquery
<dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.5.1</version> </dependency>
访问地址:http://localhost:8080/webjars/jquery/3.5.1/jquery.js 后面地址要按照依赖里面的包路径。
22、web场景-welcome与favicon功能
欢迎页支持
- 静态资源路径下 index.html。
-
- 可以配置静态资源路径
- 但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默认访问
spring: # mvc: # static-path-pattern: /res/** 这个会导致welcome page功能失效 resources: static-locations: [classpath:/haha/]
- controller能处理/index。
自定义Favicon
指网页标签上的小图标。
favicon.ico 放在静态资源目录下即可。
spring: # mvc: # static-path-pattern: /res/** 这个会导致 Favicon 功能失效
23、web场景-【源码分析】-静态资源原理
未看