目录
Spring Boot
Spring Boot 是一个脚手架(而非框架),构建于Spring框架(Framework)基础上,基于快速构建理念,提供了自动配置功能,可实现开箱即用特性(即创建完一个基本的项目以后,可以零配置或者少配置即可运行我们的项目),其核心主要有如下几个方面:
- 起步依赖(Starter Dependency)
- 自动配置(Auto Configuration)
- 健康检查(Actator)-监控
其中,Spring Boot官方地址是https://spring.io/projects/spring-boot。
准备工作
-
工具下载
1)下载jdk1.8,并进行环境变量配置(教程https://blog.csdn.net/renlianggee/article/details/90023464)
2)下载新版maven(例如apache-maven-3.6.3,网址http://maven.apache.org/),并解压
3)下载sts最新版,(例如sts-4.4.5.RELEASE,网站https://spring.io/tools)并解压。(新版本下载下来是一个jar文件,需要在jar文件所在的目录中,以命令行方式执行java-jar 下载的文件名的方式进行解压,需要实现启动系统自带的命令行客户端,然后切换到软件所在目录。
sts是一个集成开发工具,是一个定制版的Eclipse,专为Spring开发定制的,方便创建调试运行维护Spring应用
-
工作区准备
定义新的工作区(要求没有中文目录)
建议:将下载的所有文件存储到同一目录并解压,方便管理。
Maven基本配置
开maven -- conf -- setting.xml 文件,进行如下配置
1)配置maven的本地库,(保存从maven远程服务器下载的资源存储到的位置)
${user.home} 是c盘中用户文件夹
2)配置maven私服(镜像仓库)(当maven项目中需要依赖jar包时,如果本地仓库中没有,就会到镜像仓库去下载jar包 )
配置到mirrors标签内部
3)配置maven的profile(JDK版本)
配置在profiles标签内部
1.STS整合maven资源
以下配置均在Windows -- Preferences 目录下
1)启动STS(SpringToolSuite4.exe)
2)配置Maven Installations(Maven -- Installtions -- add -- 输入或浏览maven下载路径)
3)配置Maven User Settings ( Maven -- User Settings -- 输入或浏览settings.xml路径)
4)设置工作区编码( General -- Workspace -- Text file encoding -- Other 设置为UTF-8)
2.STS工具使用基本优化
2.1禁用拼写检查
(General -- Editors -- Text Editors -- Spelling -- Enable spell checking)
2.2取消连接选项配置
(General -- Editors -- Text Editors -- Hyperlinking)
2.3关闭校验功能
(Gender -- JSON -- Validation)
2.4修改STS工具内存配置
打开sts安装目录,打开SpringToolSuite4.ini文件,修改堆大小
-vmargs:说明后面是VM的参数
-Xms64m :虚拟机占用系统的最小内存
-Xmx128m:虚拟机占用系统的最大内存
Sprng Boot 快速入门
1.项目创建及结构分析
普通eclipse创建springboot项目:
https://start.spring.io--> 输入内容 --> generate --> 下载解压 -->
eclipse --> import --> general --> existing projects into workspace --> 导入项目
打开STS,创建spring boot 项目;
第一步:File -- new -- Spring Starter Project -- next
第二步:填写项目的基本信息
第三步:选择Spring Boot 版本
SNAPSHOT: 快照版,可以稳定使用,且该版本会一直进行小量的优化和改进
点击finish后,项目便开始从maven配置中指定的私服服务器(例如我配置的阿里云私服)去下载起步依赖(spring boot项目中默认指定了项目启动时需要的一些jar包依赖),第一次启动时,这个过程可能会比较耗时,假如指定版本的spring boot项目之前创建过,会默认从本地库中查找,假如本地库没有,则去远程库下载,项目创建成功之后,其包视图(Package Explorer)结构如下(Window -- Show View 中可以找到包视图):
其中呈现的项目结构中,所有的类和配置文件都是创建好项目后,又STS工具帮我们自动创建的。
2.项目启动过程分析
找到项目的入口类(启动类 ,使用@SpringBootAppliation注解描述的类,有且只有一个),然后运行启动类,检测启动过程,控制台会出现如图标识:
分析项目启动时发生了什么:
- 由@SpringBootApplication注解描述的类是一个启动入口类,这个类在启动时会扫描类,找到指定包下的类,从classpath(类路径寻找),classpath就是.class文件所在的路径;
- 找到后,将这些类从disk(磁盘)中load class (加载)到内存中,加载时通过线程调用IO把类读到内存中;
- 加载后会创建很多Class类型的对象,并对对象进行分析,查看类上是否有指定的注解描述(Spring框架给定的注解),就是对类进行了标识,方便Spring知道是否需要创建和管理这些类的对象;
- Spring管理对象,通过BeanFactory工厂创建对象,目的是通过对象去储存数据,执行业务,此工厂对象会基于反射创建Bean的实例;假设此Bean指定了生命周期方法,还会调用生命周期方法,当实例创建后,Spring框架会基于类的作用域描述,将实例储存到不同作用域的容器中;
- 为了科学的使用对象,Spring可能会将对象储存到Bean pool(池,内部是Map格式,Spring中有很多不同的池),下次需要对象时直接调用,不需要再此创建,提高对象的应用效率;通过ApplicationContext 管理池。
Bean池用到了亨元模式,(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。池技术,String常量池、数据库连接池、缓冲池等等都是享元模式的应用。
项目启动时会做哪些事呢:
a)加载类(将类的信息从磁盘读到内存):线程+IO
b)创建字节码对象(其类型是Class类型)用于存储类的字节码信息
c)基于字节码对象获取类上的注解信息(@Component,@Controller,@Service 等),判定此类是否要交给Spring管理
d)假如是交给Spring管理的对象,Spring框架会创建其对象然后赋予其特性
e)基于配置文件(例如application.properties)以及Spring Boot提供的自动配置对对象进行初始化应用
3.项目业务初步实现及测试
3.1 代码存放规则
Spring Boot项目工程中代码的结构,我们写的类需要按照怎样的规则进行存放:
- 业务代码放在src/main/java目录下的启动类(被@SpringBootApplication注解)的所在包或者子包中,需要使用特定的注解进行描述,例如(@Component,@Service,@Controller)
- 测试类代码放在src/test/java目录下,启动类所在的包或者子包中,需要使用@SpringBootTest注解进行描述,且注解导入的包必须是org.junit.jupiter.api.Test
3.2 业务实现
基于Spring Boot脚手架,通过Spring框架进行Bean对象的管理实现
第一步:创建一个DefauktCache类并交给Spring管理
package com.cy.pj.common.cache;
import org.springframework.stereotype.Component;
@Component
public class DefaultCache {
}
其中,@Component是Spring中用于描述Bean类的一个注解,用于告诉Spring这个类的实例由Spring创建,当此对象由Spring创建和管理时,默认会将对象储存到池(Bean池) 中。
第二步:添加Spring Boot测试类,进行bean的获取及测试,要放在test目录中:
package com.cy.pj.common.cache;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class DefaultCacheTests {
@Autowired
private DefaultCache defaultCache;
@Test
void testCache() {
System.out.println(defaultCache);
}
}
其中:
- @SpringBootTest 注解用于告诉Spring框架,此测试类交给Spring管理
- @Autowired 注解用于自动导入对象到类中,被注入进的类同样要被 Spring 容器管理
第三步:代码设计及运行分析,如下图
上图描述了DefaultCacheTests类与DefaultCache类的关系,这两个类通过指定注解(@SpringBootTest,@Component)进行了描述,意图是告诉Spring框架这两个实例的创建由Spring负责,并且由Spring框架基于@Autowired注解的描述完成DefaultCacheTests实例中有关DefaultCache类型的值的注入(DI)(在测试类中写一个单元测试方法,在方法内部获取这个对象),会从Spring容器(Spring IOC Container)中获取。通过@Autowired注解,标识测试类和普通类之间是has a 的关系,由Spring框架赋值;进行DI注入时会先进行DL查找(Dependency lookup),查找是否这个类型的对象,有就继续执行依赖注入(dependency injection)。
第四步:为对象设计作用域,设置延迟加载,设置生命周期方法
在Spring框架中,Spring为由它创建和管理的对象,设计了一些特性,例如:作用域、延时加载、生命周期方法等,基于这些特性先堆Bean对象的管理。
package com.cy.pj.common.cache;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("singleton")//默认单例作用域
@Lazy
public class DefaultCache {
public DefaultCache() {
System.out.println("cache()");
}
@PostConstruct
public void init() {
System.out.println("init()");
}
@PreDestroy
public void destory() {
System.out.println("destory()");
}
}
其中:
- @Scope 是Spring中用于定义Bean对象作用域的一个注解,其常用的值有
- singleton:@Scope("singleton")单例作用域,此作用域的对象在内存中只存在一份,通过共享设计(池),实现对象的可重用性。 此对象何时创建由懒加载(Lazy)特性设计决定,是否可以被销毁由spring框架决定(一般在容器销毁时销毁),适合应用频度比较高的对象
- prototype:@Scope("prototype")多例作用域,此作用域的对象在需要时创建,默认是延迟加载,和懒加载特性无关,每次从容器获取都是一个新的对象,但spring框架不负责销毁,适合应用频度比较低的对象
- @Lazy 注解用于描述类,其目的是告诉Spring框架此类支持延迟加载,通常会配合单例作用域使用
- @PostConstruct 注解用于描述Bean对象生命周期方法中初始化方法,此方法会在对象的构造方法之后执行
- @PreDestroy 注解用于描述Bean对象生命周期方法中的销毁方法,此方法会在对象销毁之前执行(当作用域为prototype时,此方法不会执行)
第五步:通过测试类测试作用域,延迟加载,生命周期方法
package com.cy.pj.common.cache;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class DefaultCacheTests {
@Autowired
private DefaultCache defaultCache;
@Test
void testCache() {
System.out.println(defaultCache);
//先执行构造方法,再执行@PostConstruct ,创建对象,然后指向@PostConstruct,最后执行@PreDestroy
//输出cache() init() com.cy.pj.common.cache.DefaultCache@29539e36 destory()
}
}
Spring是一个资源整合框架(FrameWork),通过Spring可以将很多资源(自己写的对象或第三方提供的对象,例如连接池等)整合再一起,然后进行科学应用,以便更好的对外提供服务,如下图
3.3 bean对象的三大特性
Spring管理bean对象,会为bean赋予三大特性:
1)延迟加载:暂缓对象的加载,在需要创建的时候才创建
优点:可以优化资源的使用
缺点:用时在创建可能会导致响应速度降低,造成卡顿现象
应用场景:资源有限,对象较大,且使用稀少,则可以懒加载就懒加载
实现:需要在需要懒加载的对象类型上使用@Lazy注解进行描述
2)作用域:spring框架为对象提供的作用范围,此对象的生命周期只能在指定范围内有效
优点:让对象在有效范围发挥作用,尽量控制对象的创建和销毁以保证对象的高效和低耗的运行
缺点:框架的设计难度会加大,应用不熟练会导致作用域冲突
应用场景:不同业务的作用域的设计不同(例如:对象在整个项目中应用频繁,可以考虑单例作用域,若使用稀少,可以考虑多例作用域)
实现:在需要设定作用域的类上使用@Scope注解进行描述
@Scope("singleton")单例作用域。此作用域的对象在内存中只存在一份,通过共享设计(亨元模式),实现对象的可重用性,此对象何时创建由懒加载特性设计决定,是否可以被销毁由spring框架决定(一般在容器销毁时销毁),适合应用频度较高的对象
@Scope("prototype")多例作用域,此作用域的对象在需要是创建,和懒加载特性无关,每次从容器获取,但spring框架部负责销毁,适合应用频度较低的对象
3)生命周期方法:每个对象都有生命周期,但不是每个对象都会设置生命周期方法
理解:生命周期方法是在对象生命周期过程中要执行的一些方法
目的:设计生命周期方法是为了在对象的生命周期的不同阶段执行不同的业务(例如:servlet中的init,service,destory)
设计方法:spring框架中使用相关注解对生命周期方法进行描述
@PostConstruct:描述生命周期的初始化方法,在构造方法执行之后执行,用于实现一些资源的初始化
@PreDestory:描述生命周期销毁方法,在对象销毁之前执行
思考
思考1:Java中的对象什么情况下会被回收(GC)?被谁回收?如何确定这个对象要被回收? finalize()的作用?GC系统什么时候触发?
- 没有任何引用指向这个对象时,这个对象会被认为是垃圾对象,且触发了GC时,此对象会被JVM中的垃圾回收系统(GC系统)进行回收(释放内存)。
- 触发GC操作:GC系统触发时会对内存中的对象进行可达性分析,就是检测是否还有引用访问到此对象,假如不能通过任何用访问到此对象那么这对象会被标记为垃圾对象。
- 可达性分析:通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为“引用链”,当一个对象到 GC Roots 没有任何的引用链相连时(从 GC Roots 到这个对象不可达)时,证明此对象不可用。
- finalize方法会在对象被回收(GC)之前执行,可以对对象的回收进行监控,也可以在对象回收之前进行一些资源释放操作。
- 手动GC:System.gc();
- 自动GC:当满足GC条件时或者说内存达到一定的GC启动标准时会触发GC
可达性分析(引用类型):https://blog.csdn.net/luzhensmart/article/details/81431212
思考2:当对象存在引用时,是否可能在系统触发GC之前被回收?
可能,要看引用类型,在Java中,我们可以使用的对象引用方法有四种:
- 强引用(StrongReference):此引用引用的对象,生命力最强(只要有引用指向这对象,就不能被GC)
- 软引用(SoftReference):此引用引用的对象,在内存不足时可能被GC
- 弱引用(WeakReference):此引用引用的对象,在GC执行时可能被直接销毁(即使是内存充足)
- 虚引用(PhantomReference):用的最少,类似没有引用,主要记录对象的销毁情况
说明:弱引用和软引用一般用在缓存产品的设计中
思考3:当GC系统没有启动时,对象是否可能被回收?
可能看对象分配的位置。Java中大多数对象都会被存储在(Heap)中,但对一些没有逃逸的小对象,现在也有可能分配在栈上(JVM发展历程的域一种新的优化方法)。
未逃逸对象:方法外界没有引用指向此对象时,此对象是未逃逸对象,分配在栈上。在栈上分配的对象,方法调用结束,对象销毁,不会启用GC
逃逸对象:方法外部有引用指向此对象时,此对象是逃逸对象,分配在堆上,对象的回收需要GC系统回收
JDK8中会打开逃逸分析选项,希望未逃逸的对象分配到栈上,避免GC系统的启用。
拓展:JVM参数:-XX:+PrintGCDetails:打印GC详情
3.4 项目业务增强实现及测试
第一步:定义业务Cache接口
package com.cy.pj.common.cache;
public interface Cache {
}
第二步:定义WeakCache实现Cache接口
package com.cy.pj.common.cache;
import org.springframework.stereotype.Component;
//@Component("cache")
@Component()//假设没有取名,默认为类名,然后首字母小写,例如softCache
public class WeakCache implements Cache {
public WeakCache() {
System.out.println("==WeakCache==");
}
}
第三步:创建或修改SoftCache,让此类也实现Cache接口
package com.cy.pj.common.cache;
import org.springframework.stereotype.Component;
@Component
public class SoftCache implements Cache {
public SoftCache() {
System.out.println("==SoftCache==");
}
}
第四步:创建单元测试类测试
package com.cy.pj.common.cache;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class CacheTests {
/**
* @Autowried规则:先基于属性类型查找对象进行注入,假如类型有多个,在基于属性名进行注入
* @Qualifier:需要配合@Autowried注解使用,不能单独使用,且按bean的名字进行注入
*/
@Autowired
@Qualifier("weakCache")
private Cache cache;
@Test
void testCache() {
System.out.println(cache);
}
}
业务测试运行原理分析,如下图:
图解:Cache是一个接口,有两个实现类分别是SoftCache和WeakCache,is a 表示这两个实现类是Cache类型的对象,@Component表示是将类的实现创建交给Spring管理,对象会存在Spring Bean Pool 池中(默认是单例作用域)。CacheTest由@SpringBootTest注解描述此测试类交给Spring管理,测试类中用@Autowored注解告诉Spring框架查找Cache类的对象并将对象注入(DI)给测试类,是has a 的关系。
思考:
@Autowired注解应用规则?@Qualifier注解的作用是什么?
@Autowired由spring框架对应,用于描述类中属性或者相关方法。spring框架在项目运行时假如发现由他管理的Bean对象中有使用@Autowired注解描述的属性或方法,可以按照制定规则为属性赋值(DI)。其基本规则是:首先要检测容器中是否有与属性或方法参数类型相匹配的对象,假如有并且只有一个则直接注入。其次,假如检测到有多个,会按照@Autowired注解描述的属性或方法参数名查找是否有名字匹配的对象,有则直接注入,没有则抛出异常。最后,假如我们有明确要求,必须要注入指定类型,名字是指定名字的对象,我们可以使用@Qualifier注解对其属性或参数进行描述(此注解必须配合@Autowired注解使用),且@Qualifier注解描述的类必须的由Spring管理的类。
另外也可以通过@Autowired注解构造方法来决定Bean对象的依赖注入,如下:
package com.cy.pj.common.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import com.cy.pj.common.cache.Cache;
@Component
public class SearchService {
private Cache cache;
/* 构造方法注入 */
@Autowired
public SearchService(@Qualifier("softCache") Cache cache) {
this.cache=cache;
System.out.println("this.cache"+cache);
}
}
Spring Boot基础
Spring Boot整合外部资源
1.Spring Boot 整合连接池
1.1 概述
实际开发中应用程序与数据库交互时,“获取连接”或“释放资源”是非常消耗系统资源得两个过程,为了解决此类性能问题,通常情况我们采用连接池技术来常用连接Connection对象,如下图:
Java为数据库连接池提供了公共的接口:javax.sql.DateSource,各个厂商需要让自己的连接池实现这个接口。然后我们的应用程序在耦合与这个接口,便可以方便的切换不同厂商的连接池,常见的连接池有DBCP、C3P0、DRUID、HikariCP等。
通过连接池获取连接的一个基本过程如下图: