《学透Spring》
从入门到项目实战
数据资料: 《学透Spring》
一、初识Spring
Spring FrameWork
、Spring Boot
、Spring Cloud
、Spring Data
注意各模块的依赖版本支持情况,以及框架支持的JDK版本情况
Spring Initializr:官方Initializr和Aliyun Initializr
二、Spring FrameWork中的IoC容器
2.1 IoC容器基础知识
2.1.1 IoC容器
2.1.2 容器初始化步骤
步骤 | 内容 |
---|---|
1 | 从xml文件、Java类或其他地方加载配置元数据 |
2 | 通过BeanFactoryPostProcessor对配置元数据进行一轮处理 |
3 | 初始化Bean实例,并根据给定的依赖关系组装对象 |
4 | 通过BeanPostProcessor对Bean进行处理,器件会粗发Bean被构造后的回调 |
xml文件方式初始化IoC容器
|
|
|
|
2.1.3 BeanFactory与ApplicationContext
ApplicationContext继承BeanFactory,增加企业级应用所需的更多特性,通过ApplicationContext发挥Spring上下文的能力
|
|
2.1.4 容器的继承
容器继承:子上下文可以看到父上下文定义的Bean,反之则不行;可以定义同ID的Bean,各自都能获取自己定义的Bean。
|
|
2.2 Bean基础知识
2.2.1 Bean
Bean是指Java中的`可重用软件组件`
- Bean的名称
- Bean的具体类信息,全限定类名
- Bean的作用域,单例(每次都是同一个对象)还是原型(每次都是一个新对象)
- 依赖注入相关信息,构造方法参数、属性以及自动织入方式
- 创建销毁相关信息,懒加载模式、初始化回调方法和销毁回调方法
2.2.2 Bean的依赖关系
两种注入方式:基于构造方法
的注入和基于Setter方法
的注入
方法 | java类模块 | xml样例 |
---|---|---|
构造方法 | public Hello(String name){} |
<bean ...><constructor-arg value="李雷"/></bean> 1 |
Setter方法 | private String name |
<bean ...><property value="李雷"/></bean> |
自动织入:自动织入方式可选no、byName、byType和constructor;多个候选Bean可选配置
autowire-candidate
为false、配置目标Bean注解@Primary
Bean初始化顺序:
<bean/>
的depends-on
属性或代码的@DependsOn
2.2.3 Bean的三种配置方式
基于xml文件的配置
|
|
scope声明Bean作用域,lazy-init声明是否懒加载,depends-on声明初始化顺序
基于注解的配置
类别 | 详情 |
---|---|
Bean创建 | @Compent @Service @Repository @Controller (@RestController ) |
可注入依赖 | @Autowire @Resource @Inject @Value (注入环境变量) |
基于Java类的配置
|
|
2.3 定制容器与Bean的行为
2.3.1 Bean的生命周期
Bean的生命周期中可定制方法
初始化 | 销毁 |
---|---|
添加了@PostConstrut 的方法 |
添加了@PreDestory 的方法 |
实现了InitializingBean的afterPropertiesSet()方法 | 实现了DisposableBean的destory()方法 |
<bean/> 的init-method或@Bean中的initMethod |
<bean/> 的destroy-method或@Bean中的destroyMethod |
其中自动推测销毁Bean时的方法:
public void close(){}
或public void shutdown
- 实现
AutoClosable
或Closable
接口的close()
方法
|
|
2.3.2 Aware接口的应用
让Bean感知到容器的诸多信息
例如实现ApplicationContextAware接口用于在Bean中获取容器信息、实现ApplicationEventPublisherAware接口用于荣容器中获取ApplicationEventPublisher实例。
2.3.3 事件机制
容器变动,以ApplicationEvent的子类,在实现ApplicationListener的Bean中(或使用@EventListener)处理变更。
多个Bean处理同一个事件,通过
order
注解指定处理顺序
|
|
2.3.4 容器的拓展点
BeanPostProcessor:Bean的后置处理器接口(初始化前执行postProcessBeforeInitialization()、初始化后执行postProcessAfterInitiazation())
BeanFactoryPostProcessor:BeanFactory的后置处理器,BeanFactory加载所有Bean定义但未初始化时执行postProcessBeanFactory()方法
2.3.5 优雅的关闭容器
方式1:让Bean实现Lifecycle接口处理容器的变更;方式2:借助Spring FrameWork的事件机制
|
|
2.4 容器中的几种抽象
2.4.1 环境抽象
Profile抽象:
xml方式 | 代码方式 | 环境变量 | |
---|---|---|---|
配置 | <beans/> 的profile属性 |
@Profile注解在@Configuation注解的类上 @Profile注解在@Bean注解的方法上 |
|
启用 | ConfigurableEnvironment.setActiveProfiles() 指定激活的profile |
配置文件指定spring.profiles.active 环境变量的值 |
PropertySource抽象:添加属性来源
方式 | 样例 |
---|---|
xml | <context:property-placeholder location:"classpath:/META-INF/resources/app.properties" /> |
注解 | @Configuration @PropertySource("classpath:/META-INF/resources/app.properties") |
2.4.2 任务抽象
异步执行: 统一的TaskExcutor方便配置多线程相关的细节
相关实现:同步的SyncTaskExcutor、SimpleAsyncTaskExecutor、ConcurrentTaskExecutor、ThreadPoolTaskExecutor
定时任务:统一的TaskSchduler方便处理特定时间执行和多次重复执行
xml方式:
<task:scheduler id="taskScheduler" pool-size="10: />
代码方式:使用@EnableSchduling启用后使用@Schduled注解方法启用特定定时任务
三、Spring Framework中的AOP
3.1 Spring中的AOP
3.1.1 AOP的核心概念
AOP(Aspect Oriented Programming,面向切面编程)。
概念 | 说明 |
---|---|
切面(aspect) | 按关注点进行模块分解时,横切关注点就表示一个切面 |
连接点(join point) | 程序执行的某一刻,在这个点上可以添加额外的动作 |
通知(advice) | 切面在特定连接点上执行的动作 |
切入点(pointcut) | 切入点是用来描述连接点的,他决定了当前代码与连接点是否匹配 |
3.1.2 Spring AOP的实现原理
Spring AOP的核心技术:动态代理技术(23种经典设计模式之一),在运行时动态的为对象创建代理的技术。
在Spring中,由AOP框架创建,用来实现切面的休想被成为AOP代理(AOP Proxy),一般采用JDK动态代理或者是CGLIB代理。
技术 | 必须要实现接口 | 支持拦截public方法 | 支持拦截protected方法 | 拦截默认作用域方法 |
---|---|---|---|---|
JDK动态代理 | 是 | 是 | 否 | 否 |
CGLIB代理 | 否 | 是 | 是 | 是 |
JDK代理实现在调用前后打印内容
|
|
使用代理模式中的小坑
如果存在一个类的内部方法调用,这个调用的对象不是代理,而是其本身,则无法享受AOP增强的效果。
|
|
3.2 基于@AspectJ的配置
核心步骤
步骤 | 说明 |
---|---|
1 | 引入org.springframework:spring-aspects 依赖 |
2 | 启用@AspectJ支持,注解形式@EnableAspectJAutoProxy 2,xml形式<aop:aspcetj-autoproxy/> |
3 | 声明切面,注解形式@Aspect |
3.2.1 声明切入点
由两部分组成:切入点表达式(描述要匹配的连接点)和切入点方法签名(引用切入点,方便切入点的复用)。
切入点表达式注解@Pointcut及其常用的切入点标识符(pointcut designator,PCD3)4
PCD | 说明 |
---|---|
execution | 最常用的一个PCD,用来匹配特定方法的执行 |
within | 匹配特定范围内的类型,可以用通配符来匹配某个Java包内的所有类 |
this | Spring AOP代理对象这个Bean本身要匹配某个给定的类型 |
target | 目标对象要匹配某个给定的类型,比this更常用一些 |
args | 传入的方法参数要匹配某个给定的类型,它也可以用来绑定请求参数 |
bean | SpringAOP特有的一个PCD,匹配Bean的ID或名称,可以用通配符 |
针对注解的常用PCD
PCD | 说明 |
---|---|
@target | 执行的目标对象带有特定类型的注解 |
@args | 传入的方法参数带有特定类型注解 |
@annotation | 拦截的方法上带有特定类型注解 |
|
|
3.2.2 声明通知
同时存在多个通知作用域同一处,可是让切面实现Orderd接口或则添加@Order注解
前置通知@Before
:方法没有返回值、可以对被拦截方法的参数进行加工
|
|
后置通知@AfterReturning
、@AfterThrowing
、@After
:方法执行后,可能正常返回,也可能抛出异常
|
|
环绕通知@Around
:在方法执行前后加入自己的逻辑、替换方法本身的逻辑、替换调用参数。第一个参数必须是ProceedingJoinPoint
类型,方法的返回类型是被拦截方法的返回类型。
|
|
引入通知@DeclareParents
:为Bean添加新的接口,并为新增的方法提供默认实现,这种操作称为引入。
|
|
3.2.3 基于@AspectJ的示例
声明原始Bean
|
|
声明切面:实现前置通知
|
|
第二个切面:实现后置通知、环绕通知(并调用引入的接口)和引入通知
|
|
GoodBye接口及相关默认实现
|
|
运行代码
|
|
单元测试:Spring中单元测试依赖spring-test、junit-jupiter依赖,可配合maven-surefire-plugin插件,使用mvn test
通过maven来执行测试
3.3 基于XML Schema的配置
Spring AOP相关的XML配置都放在<aop:config/>
中5
内容 | 关键XML |
---|---|
声明切入点 | <aop:pointcut/> |
前置通知 | <aop:before/> |
后置通知 | <aop:after-returning/> 、<aop:after-throwing/> 、<aop:after/> |
环绕通知 | <aop:around/> |
引入通知 | <aop:declare-parents/> |
|
|
|
|
四、从Spring Framework到Spring Boot
如果一个东西可以生成出来,那为什么还要生成它呢?
4.1 SpringBoot 基础知识
组成部分
组成 | 说明 | 备注 |
---|---|---|
起步依赖 | 解决依赖管理难题 | 可通过mven dependcy:tree 查看Maven的依赖信息 |
自动配置 | 为依赖提供常规的默认配置,消除模板化的配置 | |
Spring Boot Actuator | 提供一系列在生产环境运行时所需的特性 | |
命令行CLI |
两种引入springboot的方式
继承starter-parent | 无法继承starter-parent | |
---|---|---|
引入方式 | <parent> |
<dependency> |
打包插件 | 引入即可,版本已在starter中定义 | 引入spring-boot-maven-plugin 并指定版本 |
4.2 起步依赖
springboot内置的起步依赖:spring-boot-starter开头(应避免使用这个前缀)
名称 | 描述 |
---|---|
spring-boot-starter | 核心功能,比如自动配置、配置加载等 |
spring-boot-starter-actuator | 各种生产级特性 |
spring-boot-starter-aop | Spring AOP相关支持 |
spring-boot-starter-data-jpa | Spring Data JPA相关支持,默认使用Hibernate作为JPA实现 |
spring-boot-starter-data-redis | Spring Data Redis相关支持,默认使用Lettuce作为Redis客户端 |
spring-boot-starter-jdbc | Spring的jdbc支持 |
spring-boot-starter-logging | 日志依赖,默认使用Logback |
spring-boot-starter-security | Spring Security相关支持 |
spring-boot-starter-test | 在Spring项目中进行测试所需的相关库 |
spring-boot-starter-web | 构建Web项目所需的各种依赖,默认使用Tomcat作为内嵌容器 |
如果想要升级依赖的版本,可在
org.springframework.boot:spring-boot-dependencies
的pom.xml中寻找相关的版本声明,或直接在<dependencies/>
中直接引入所需的依赖,同时在起步依赖中排除所加的依赖。
异步依赖的实现原理:Maven的依赖传递机制,在Maven的<dependencyManagement/>
中统一定义依赖的信息(比如版本、排除的传递依赖项等),随后在<dependencies/>
中添加依赖就不用重复配置这些信息。
4.3 自动配置
@SpringBootApplication注解中添加了@EnableAutoConfiguration注解,开启了自动配置功能。
4.3.1 自动配置的实现原理
实现原理:
自动配置类其实就是添加了@Configuration的普通Java配置类,例如加入了条件注解@Conditional来实现“根据特定条件启用相关配置类”。附:SpringBoot条件注解的底层实现原理
引入不在扫描路径中的自动配置类:
秘密在于@EnableAutoConfiguration的@Import(AutoConfigurationImportSelector.class),通过SpringFactoiesLoader加载/META-INF/spring.factories里配置的自动配置类列表。
禁用某些自动配置:
- 在配置文件中使用spring.actuoconfig.exclude配置项,值是要排除的自动配置类的全限定类名
- 在@SpringBootApplication注解中添加exclude配置,值是要排除的自动配置类。