核心特性(Core)
IoC容器(IoC Container)
Spring事件(Events)
资源管理(Resources)
国际化(i18n)
校验(Validation)
数据绑定(Data Binding)
类型转换(Type Conversion)
Spring表达式(Spring Express Language)
面向切面编程(AOP)
数据存储(Data Access)
- JDBC
- 事务抽象(Transactions)
- DAO支持(DAO Support)
- O/R映射(O/R Mapping)
- XML编程(XML Marshalling)
Web技术
- Web Servlet 技术栈
Spring MVC
WebSocket
SockJS
- Web Reactive技术栈
Spring WebFlux
WebClient
WebSocket
技术整合(Integration)
远程调用(Remoting)
Java消息服务(JMS)
Java连接架构(JCA)
Java管理扩展(JMX)
Java邮件客户端(Email)
本地任务(Tasks)
本地调度(Scheduling)
缓存抽象(Caching)
Spring测试(Testing)
测试(Testing)
模拟对象(Mock Objects)
TestContext框架(TestContext Framework)
Spring MVC测试(Spring MVC Test)
Web测试客户端(WebTestClient)
Java 版本依赖与支持
Spring Framework 版本 | Java 标准版 | Java 企业版 |
---|---|---|
1.x | 1.3+ | J2EE 1.3+ |
2.x | 1.4.2+ | J2EE 1.3+ |
3.x | 5+ | J2EE 1.4 和 Java EE 5 |
4.x | 6+ | Java EE 6 和 7 |
5.x | 8+ | Java EE 7 |
Spring 模块化设计(Modular)
spring-aop
spring-aspects
spring-context-indexer
spring-context-support
spring-context
spring-core
spring-expression
spring-instrument
spring-jcl
spring-jdbc
spring-jms
spring-messaging
spring-orm
spring-oxm
spring-test
spring-tx
spring-web
spring-webflux
spring-webmvc
spring-websocket
Java 语法变化
Spring 对 Java 语言特性运用
- Java 5 语法特性
语法特性 | Spring 支持版本 | 代表实现 |
---|---|---|
注解(Annotation) | 1.2+ | @Transactional |
枚举(Enumeration) | 1.2+ | Propagation |
for-each 语法 | 3.0+ | AbstractApplicationContext |
自动装箱(AutoBoxing) | 3.0+ | |
泛型(Generic) | 3.0+ | ApplicationListener |
- Java 6 语法特性
语法特性 | Spring支持版本 | 代表实现 |
---|---|---|
接口@Override | 4.0+ |
- Java 7 语法特性
语法特性 | Spring 支持版本 | 代表实现 |
---|---|---|
Diamond 语法 | 5.0+ | DefaultListableBeanFactory |
try-with-resources 语法 | 5.0+ | ResourceBundleMessageSource |
- Java 8 语法特性
语法特性 | Spring 支持版本 | 代表实现 |
---|---|---|
Lambda 语法 | 5.0+ | PropertyEditorRegistrySupport |
Spring 对 JDK API 实践
- < Java 5 API
API 类型 | Spring 支持版本 | 代表实现 |
---|---|---|
反射(Reflection) | 1.0+ | MethodMatcher |
Java Beans | 1.0+ | CachedIntrospectionResults |
动态代理(Dynamic Proxy) | 1.0+ | JdkDynamicAopProxy |
- Java 5 API
API类型 | Spring支持版本 | 代表实现 |
---|---|---|
XML处理(DOM,SAX....) | 1.0+ | XmlBeanDefinitionReader |
Java 管理扩展(JMX) | 1.2+ | @ManagedResource |
Instrumentation | 2.0+ | InstrumentationSavingAgent |
并发框架(J.U.C) | 3.0+ | ThreadPoolTaskScheduler |
格式化(Formatter) | 3.0+ | DateFormatter |
- Java 6 API
API类型 | Spring 支持版本 | 代表实现 |
---|---|---|
JDBC4.0(JSR 221) | 1.0+ | JdbcTemplate |
Common Annotations(JSR 250) | 2.5+ | CommonAnnotationBeanPostProcessor |
JAXB 2.0(JSR 222) | 3.0+ | jaxb2Marshaller |
Scripting in JVM (JSR 223) | 4.2+ | StandardScriptFactory |
可插拔注解处理 API (JSR 269) | 5.0+ | @Indexed |
Java Compiler API (JSR 199) | 5.0+ | TestCompiler(单元测试) |
- Java 7 API
API 类型 | Spring 支持版本 | 代表实现 |
---|---|---|
Fork/Join框架(JSR 166) | 3.1+ | ForkJoinPoolFactoryBean |
NIO 2 (JSR 203) | 4.0+ | PathResource |
- Java 8 API
API 类型 | Spring 支持版本 | 代表实现 |
---|---|---|
Date and Time API(JSR 310) | 4.0+ | DateTimeContext |
可重复Annotations (JSR 337) | 4.0+ | @PropertySources |
Stream API (JSR 335) | 4.2+ | StreamConverter |
CompletableFuture(J.U.C) | 4.2+ | CompletableToListenableFutureAdapter |
Spring 对 Java EE API 整合
- Java EE Web 技术相关
JSR 规范 | Spring 支持版本 | 代表实现 |
---|---|---|
Servlet + JSP(JSR 035) | 1.0+ | DispatcherServlet |
JSTL(JSR 052) | 1.0+ | JstlView |
JavaServer Faces(JSR 127) | 1.1+ | FacesContextUtils |
Portlet(JSR 168) | 2.0 - 4.2 | DispatcherProtlet |
SOAP(JSR 067) | 2.5+ | SoapFaultException |
WebServices(JSR 109) | 2.5+ | CommonAnnotationBeanPostProcessor |
WebSocket(JSR 356) | 4.0+ | WebSocketHandler |
- Java EE 数据存储相关
JSR规范 | Spring 支持版本 | 代表实现 |
---|---|---|
JDO(JSR 12) | 1.0 - 4.2 | JdoTemplate |
JTA(JSR 907) | 1.0+ | JtaTransactionManager |
JPA(EJB 3.0 JSR 220) | 2.0+ | JpaTransactionManager |
Java Caching API(JSR 107) | 3.2+ | JCacheCache |
- Java EE Bean 技术相关
JSR 规范 | Spring 支持技术 | 代表实现 |
---|---|---|
JMS(JSR 914) | 1.1+ | JmsTemplate |
EJB 2.0(JSR 19) | 1.0+ | AbstractStatefulSessionBean |
Dependency Injection for Java(JSR 330) | 2.5+ | AutowiredAnnotationBeanPostProcessor |
Bean Validation(JSR 303) | 3.0+ | LocalValidatorFactoryBean |
Spring 编程模型
什么是Spring Framework?
Spring makes it easy to create Java enterprise applications. It provides everything you need to embrace the Java language in an enterprise environment, with support for Groovy and Kotlin as alternative languages on the JVM, and with the flexibility to create many kinds of architectures depending on an application’s needs.
(Spring使创建Java企业应用程序变得很容易。它提供了在企业环境中使用Java语言所需的一切,支持Groovy和Kotlin作为JVM上的替代语言,并具有根据应用程序的需要创建多种体系结构的灵活性)
Spring Framework 有哪些核心模块?
- spring-core:Spring 基础API模块,如资源管理,泛型处理
- spring-beans:Spring Bean 相关,如依赖查找,依赖注入
- spring-aop:Spring AOP处理,如动态代理,AOP字节码提升
- spring-context:事件驱动,注解驱动,模块驱动等
- spring-expression:Spring 表达式语言模块
IoC的定义
In software engineering, inversion of control (IoC) is a programming principle. IoC inverts the flow of control as compared to traditional control flow. In IoC, custom-written portions of a computer program receive the flow of control from a generic framework. A software architecture with this design inverts control as compared to traditional procedural programming: in traditional programming, the custom code that expresses the purpose of the program calls into reusable libraries to take care of generic tasks, but with inversion of control, it is the framework that calls into the custom, or task-specific, code. 来源:https://en.wikipedia.org/wiki/Inversion_of_control
(在软件工程中,控制反转(IoC)是一种编程原理。IoC反转的流程与传统控制流程相比。在IoC中,计算机程序中自定义编写的部分从通用框架接收控制流。采用这种设计的软件体系结构是颠倒的控件与传统过程式编程相比:在传统编程中,自定义表示程序调用可重用库的目的的代码,以处理泛型任务,但是由于控制反转,框架调用定制的,或者特定于任务的代码)
IoC发展简介
- IoC的简史
1)、1983年,Richard E. Sweet 在《The Mesa Programming Environment》中提出“Hollywood Principle”(好莱坞原则)
2)、1988年,Ralph E. Johnson & Brian Foote 在《Designing Reusable Classes》中提出“Inversion of control”(控制反转)
3)、1996年,Michael Mattsson 在《Object-Oriented Frameworks, A survey of methodological issues》中将“Inversion of control”命名为 “Hollywood principle”
4)、2004年,Martin Fowler 在《Inversion of Control Containers and the Dependency Injection pattern》中提出了自己对 IoC 以及 DI 的理解
5)、2005年,Martin Fowler 在 《InversionOfControl》对 IoC 做出进一步的说明
Implementation techniques 小节的定义:
“ In object-oriented programming, there are several basic techniques to implement inversion of control. These are:
• Using a service locator pattern
• Using dependency injection, for example
Constructor injection
Parameter injection
Setter injection
Interface injection
• Using a contextualized lookup
• Using template method design pattern
• Using strategy design pattern
IoC主要实现策略
《Expert One-on-One™ J2EE™ Development without EJB™》提到的主要实现策略 : “IoC is a broad concept that can be implemented in different ways. There are two main types:
- Dependency Lookup: The container provides callbacks to components, and a lookup context. This is the EJB and Apache Avalon approach. It leaves the onus on each component to use container APIs to look up resources and collaborators. The Inversion of Control is limited to the container invoking callback methods that application code can use to obtain resources.
- Dependency Injection: Components do no look up; they provide plain Java methods enabling the container to resolve dependencies. The container is wholly responsible for wiring up components, passing resolved objects in to JavaBean properties or constructors. Use of JavaBean properties is called Setter Injection; use of constructor arguments is called Constructor Injection.”
IoC容器的职责
在 Overview 小节中提到:
“Inversion of control serves the following design purposes:
• To decouple the execution of a task from implementation.
• To focus a module on the task it is designed for.
• To free modules from assumptions about how other systems do what they do and instead rely on contracts.
• To prevent side effects when replacing a module.
Inversion of control is sometimes facetiously referred to as the "Hollywood Principle: Don't call us, we'll call you".”(好莱坞原则:你不要来找我,我会去找你)
通用职责
依赖处理
依赖查找
依赖注入生命周期管理
容器
托管的资源(Java Beans 或其他资源)配置
容器
外部化配置
托管的资源(Java Beans 或者其他资源)
IoC容器的实现
Java SE
Java Beans
Java ServiceLoader SPI
JNDI(Java Naming and Directory Interface)Java EE
EJB(Enterprise Java Beans)
Servlet开源
Apache Avalon(http://avalon.apache.org/closed.html)
PicoContainer(http://picocontainer.com/)
Google Guice(https://github.com/google/guice)
Spring Framework(https://spring.io/projects/spring-framework)
传统IoC容器的实现
Java Beans 作为IoC容器
特性
依赖查找
生命周期管理
配置元信息
事件
自定义
资源管理
持久化规范
JavaBeans:https://www.oracle.com/technetwork/java/javase/tech/index-jsp-138795.html
BeanContext:https://docs.oracle.com/javase/8/docs/technotes/guides/beans/spec/beancontext.html
轻量级IoC容器
《Expert One-on-One™ J2EE™ Development without EJB™》认为轻量级容器的特征 :“
• A container that can manage application code.(可以管理应用程序代码的容器)
• A container that is quick to start up.(快速启动的容器)
• A container that doesn't require any special deployment steps to deploy objects within it.(不需要任何特殊部署步骤就可以在其中部署对象的容器)
• A container that has such a light footprint and minimal API dependencies that it can be run in a variety of environments.(一个占用空间小,API依赖性最小的容器,它可以在各种环境中运行)
• A container that sets the bar for adding a managed object so low in terms of deployment effort and performance overhead that it's possible to deploy and manage fine-grained objects, as well as coarse-grained components.”(在部署工作量和性能开销方面设置非常低的添加托管对象的工具条的容器,以至于可以部署和管理细粒度的对象以及粗粒度的组件)《Expert One-on-One™ J2EE™ Development without EJB™》认为轻量级容器的好处:
• Escaping the monolithic container(逃离单片容器)
• Maximizing code reusability(最大化代码的可重用性)
• Greater object orientation(更大的面向对象)
• Greater productivity(更大的生产力)
• Better testability(更好的可测试性)
依赖查找 VS 依赖注入
- Spring Framework 对构造器注入与 Setter 的论点:
“ The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.
(Spring团队通常提倡构造函数注入,因为它允许您将应用程序组件实现为不可变的对象,并确保所需的依赖项不是null。此外,注入构造函数的组件总是以完全初始化的状态返回给客户机(调用)代码。顺便提一下,大量的构造函数参数是一种不好的代码味道,这意味着类可能有太多的责任,应该重构它们,以便更好地处理关注点的适当分离)Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection. ”
(Setter注入主要应该只用于可选的依赖项,这些依赖项可以在类中分配合理的默认值。否则,在代码使用依赖项的任何地方都必须执行非空检查。setter注入的一个好处是,setter方法使该类的对象可以稍后重新配置或重新注入。因此,通过JMX mbean进行管理是setter注入的一个引人注目的例)
- 《Expert One-on-One™ J2EE™ Development without EJB™》认为 Setter 注入的优点 :
“ Advantages of Setter Injection include:
• JavaBean properties are well supported in IDEs.
• JavaBean properties are self-documenting.
• JavaBean properties are inherited by subclasses without the need for any code.
• It's possible to use the standard JavaBeans property-editor machinery for type conversions if necessary.
• Many existing JavaBeans can be used within a JavaBean-oriented IoC container without modification.
• If there is a corresponding getter for each setter (making the property readable, as well as writable), it is possible to ask the component for its current configuration state. This is particularly useful if we want to persist that state: for example, in an XML form or in a database. With Constructor Injection, there's no way to find the current state.
• Setter Injection works well for objects that have default values, meaning that not all properties need to be supplied atruntime. ”
(Setter注入的优点包括:
•JavaBean属性在ide中得到了很好的支持
•JavaBean属性是自文档化的
•JavaBean属性由子类继承,不需要任何代码
•如果需要,可以使用标准javabean属性编辑器机制进行类型转换
•许多现有的javabean可以在一个面向javabean的IoC容器中使用,而无需修改
•如果每个setter都有相应的getter(使属性可读,也可写),则可以请求组件的当前配置状态。如果我们想要保持这种状态,这是特别有用的:例如,在XML表单或数据库中。使用构造函数注入,就无法找到当前状态
•Setter注入对于具有默认值的对象很有效,这意味着不需要提供所有属性运行时)
- 《Expert One-on-One™ J2EE™ Development without EJB™》认为 Setter 注入的缺点 :
“ Disadvantages include:
The order in which setters are called is not expressed in any contract. Thus, we sometimes need to invoke a method after the last setter has been called to initialize the component. Spring provides the org.springframework.beans.factory.InitializingBean interface for this; it also provides the ability to invoke an arbitrary init method. However, this contract must be documented to ensure correct use outside a container.
Not all the necessary setters may have been called before use. The object can thus be left partially configured. ”
(缺点包括:
调用setter的顺序在任何契约中都没有表示。因此,我们有时需要在调用最后一个setter后调用方法来初始化组件。Spring提供了org.springframe .bean .factory.InitializingBean接口;它还提供了调用任意init方法的能力。然而,该合同必须形成文件,以确保在容器外正确使用。并非所有必需的setter可能在使用之前都已被调用。因此,可以保留对象的部分配置)
- 《Expert One-on-One™ J2EE™ Development without EJB™》认为构造器注入的优点:
“ Advantages of Constructor Injection include:
Each managed object is guaranteed to be in a consistent state—fully configured—before it can be invoked in any business methods. This is the primary motivation of Constructor Injection. (However, it is possible to achieve the same result with JavaBeans via dependency checking, as Spring can optionally perform.) There's no need for initialization methods.
There may be slightly less code than results from the use of multiple JavaBean methods, although will be no difference in complexity. ”
(构造函数注入的优点包括:
在任何业务方法中调用之前,保证每个托管对象处于一致的状态全配置状态。这是构造函数注入的主要动机。(然而,通过依赖项检查,可以用javabean实现相同的结果,Spring可以有选择地执行。)不需要初始化方法。与使用多种JavaBean方法的结果相比,代码可能稍微少一些,但是在复杂性上没有什么区别)
- 《Expert One-on-One™ J2EE™ Development without EJB™》认为构造器注入的缺点:
“ Disadvantages include:
• Although also a Java-language feature, multi-argument constructors are probably less common in existing code than use of JavaBean properties.
• Java constructor arguments don't have names visible by introspection.
• Constructor argument lists are less well supported by IDEs than JavaBean setter methods.
• Long constructor argument lists and large constructor bodies can become unwieldy.
• Concrete inheritance can become problematic.
• Poor support for optional properties, compared to JavaBeans
• Unit testing can be slightly more difficult
• When collaborators are passed in on object construction, it becomes impossible to change the reference held in the object. ”
(•尽管也是java语言的特性,但是在现有代码中,多参数构造函数可能不如使用JavaBean属性常见
•Java构造函数参数没有内省可见的名称
•ide对构造函数参数列表的支持不如JavaBean setter方法好
•长构造函数参数列表和大型构造函数主体可能变得笨拙
•具体的继承可能会有问题
•与javabean相比,对可选属性的支持较差
•单元测试可能稍微有些困难
•当合作者被传递到对象构造时,就不可能改变对象中的引用)
什么是IoC?
简单地说,IoC 是反转控制,类似于好莱坞原则,主要有依赖查找和依赖注入实现
依赖查找和依赖注入的区别?
依赖查找是主动或手动的依赖查找方式,通常需要依赖容器或标准 API实现。而依赖注入则是手动或自动依赖绑定的方式,无需依赖特定的容器和API
Spring 作为IoC容器有什么优势?
典型的IoC管理,依赖查找和依赖注入
AOP抽象
事务抽象
事务机制
SPI机制
强大的第三方整合
易测试性
更好的面向对象
Spring IoC依赖查找
根据Bean名称查找
实时查找
延时查找根据Bean类型查找
单个Bean 对象
集合Bean 对象根据Bean名称 + 类型查找
根据Java注解查找
单个Bean 对象
集合Bean 对象
Spring IoC依赖注入
根据Bean名称注入
根据Bean 类型注入
单个Bean对象
集合Bean 对象注入容器内建Bean对象
注入非Bean对象
注入类型
实时注入
延迟注入
Spring IoC 依赖来源
自定义Bean
容器内建Bean对象
容器内建依赖
Spring IoC配置元信息
Bean 定义配置
基于XML文件
基于Properties文件
基于Java注解
基于Java APIIoC容器配置
基于XML文件
基于Java注解
基于Java API外部化属性配置
基于Java 注解
BeanFactory 和 ApplicationContext 谁才是 Spring IoC 容器?
- BeanFactory 是 Spring 底层 IoC 容器
- ApplicationContext 是具备应用特性的 BeanFactory 超集
Spring 应用上下文
ApplicationContext 除了 IoC 容器角色,还有提供:
面向切面(AOP)
配置元信息(Configuration Metadata)
资源管理(Resources)
事件(Events)
国际化(i18n)
注解(Annotations)
Envirnment抽象(Environment Abstraction)
https://docs.spring.io/spring/docs/5.2.2.RELEASE/spring-framework-reference/core.html#beans-introduction
Spring IoC 容器生命周期
启动
运行
停止
什么是Spring IoC容器?
Spring Framework implementation of the Inversion of Control (IoC) principle. IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean.
(实现了Spring框架的反转控制(IoC)原则。IoC也称为依赖注入(dependency injection, DI)。在这个过程中,对象只通过构造函数参数、工厂方法的参数或对象实例构造或从工厂方法返回后在对象实例上设置的属性来定义它们的依赖项(即它们所使用的其他对象)。然后容器在创建bean时注入这些依赖项)
BeanFactory 与 FactoryBean 的区别?
BeanFactory 是 IoC 底层容器
FactoryBean 是 创建 Bean 的一种方式,帮助实现复杂的初始化逻辑
Spring IoC容器启动时做了哪些准备?
IoC 配置元信息读取和解析、IoC容器生命周期、Spring 事件发布、国际化等
定义Spring Bean
什么是BeanDefinition?
BeanDefinition 是 Spring Framework 中定义 Bean 的配置元信息接口,包含:
1、Bean 的类名
2、Bean 行为配置元素,如作用域、自动绑定的模式、生命周期回调等
3、其他Bean应用,又可称作合作者(collaborators)或者依赖(dependencies)
4、配置设置,比如Bean 属性(Properties)
BeanDefinition 元信息
属性(Property) | 说明 |
---|---|
Class | Bean 全类名,必须是具体类,不能用抽象类或接口 |
Name | Bean 的名称或者ID |
Scope | Bean 的作用域(如:singleton、prototype等) |
Constructor arguments | Bean 构造器参数(用依赖注入) |
Properties | Bean 属性设置(用于依赖注入) |
Autowiring mode | Bean 自动绑定模式(如:通过名称byName) |
Lazy initialzation mode | Bean 延迟初始化模式(延迟和非延迟) |
initialization method | Bean 初始化回调方法名称 |
Destruction method | Bean 销毁回调方法名称 |
BeanDefinition 构建
通过BeanDefinitionBuilder
通过AbstractBeanDefinition 以及 派生类
命名Spring Bean
- Bean 的名称
每个 Bean 拥有一个或多个标识符(identifiers),这些标识符在 Bean 所在的容器必须是唯一的。通常,一个 Bean 仅有一个标识符,如果需要额外的,可考虑使用别名
(Alias)
来扩充在基于 XML 的配置元信息中,开发人员可用 id 或者 name 属性来规定 Bean 的 标识符。通常Bean 的 标识符由字母组成,允许出现特殊字符。如果要想引入 Bean 的别名的话,可在name 属性使用半角逗号(“,”)或分号(“;”) 来间隔
Bean 的 id 或 name 属性并非必须制定,如果留空的话,容器会为 Bean 自动生成一个唯一的名称。Bean 的命名尽管没有限制,不过官方建议采用驼峰的方式,更符合 Java 的命名约定
- Bean 名称生成器(BeanNameGenerator)
由 Spring Framework 2.0.3 引入,框架內建两种实现:
- DefaultBeanNameGenerator:默认通用 BeanNameGenerator 实现
- AnnotationBeanNameGenerator:基于注解扫描的 BeanNameGenerator 实现,起始于Spring Framework 2.5,关联的官方文档:
With component scanning in the classpath, Spring generates bean names for unnamed components,following the rules described earlier: essentially, taking the simple class name and turning its initial character to lower-case. However, in the (unusual) special case when there is more than one character and both the first and second characters are upper case, the original casing gets preserved. These are the same rules as defined by java.beans.Introspector.decapitalize (which Spring uses here).
Spring Bean 的别名
Bean 别名(Alias)的价值:
- 复用现有的 BeanDefinition
- 更具有场景化的命名方法,比如:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
注册Spring Bean
BeanDefinition 注册
XML配置元信息
<bean name=”...” ... />Java 注解配置元信息
@Bean
@Component
@ImportJava API 配置元信息
命名方式:BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
非命名方式:
BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition,BeanDefinitionRegistry)
配置类方式:
AnnotatedBeanDefinitionReader#register(Class...)
外部单体对象注册
Java API配置元信息SingletonBeanRegistry#registerSingleton
实例化(Instantiation)Spring Bean
常规方式
通过构造器(配置元信息:XML、Java 注解 和 Java API)
通过静态工厂方法(配置元信息:XML、Java API)
通过Bean工厂方法(配置元信息:XML、Java API)
通过FactoryBean(配置元信息:XML、Java 注解 和 Java API)特殊方式
通过ServiceLoaderFactoryBean
(配置元信息:XML、Java 注解和 Java API )
通过AutowireCapableBeanFactory#createBean(java.lang.Class, int, boolean)
通过BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
初始化(Initialization)Spring Bean
@PostConstruct 标注方法
实现InitializingBean 接口的afterPropertiesSet() 方法
自定义初始化方法
XML配置:<bean init-method=”init” ... />
Java注解:@Bean(initMethod=”init”)
Java API:AbstractBeanDefinition#setInitMethodName(String)
假设以上三种方式均在同一 Bean 中定义,那么这些方法的执行顺序是:从上到下依次执行
延迟初始化 Spring Bean
Bean 延迟初始化(Lazy Initialization)
- XML配置:
<bean lazy-init=”true” ... />
- Java 注解:@Lazy(value = true)
销毁Spring Bean
Bean 销毁(Destroy)
@PreDestroy 标注方法
实现DisposableBean 接口的destroy() 方法
自定义销毁方法
XML配置:<bean destroy=”destroy” ... />
Java 注解:@Bean(destroy=”destroy”)
Java API:AbstractBeanDefinition#setDestroyMethodName(String)
垃圾回收Spring Bean
Bean 垃圾回收(GC)
1、关闭Spring 容器(应用上下文)
2、执行GC
3、Spring Bean 覆盖的finalized()方法被回调
单一类型依赖查找
单一类型依赖查找接口 - BeanFactory
根据Bean 名称查找
getBean(String)
Spring 2.5 覆盖默认参数:getBean(String,Object...)
根据Bean类型查找
Bean 实时查找Spring 3.0 getBean(Class)
Spring 4.1 覆盖默认参数:getBean(String,Object.....)
Spring5.1 Bean 延迟查找
getBeanProvider(Class)
getBeanProvider(ResolvableType)
根据Bean 名称 + 类型查找:
getBean(String,Class)
集合类型依赖查找
集合类型依赖查找接口 - ListableBeanFactory
根据Bean 类型查找
获取同类型Bean 名称列表getBeanNamesForType(Class)
Spring 4.2 getBeanNamesForType(ResolvableType)
获取同类型Bean 实例列表
getBeansOfType(Class) 以及重载方法
通过注解类型查找
Spring 3.0 获取标注类型Bean 名称列表getBeanNamesForAnnotation(Class<? extends Annotation>)
Spring 3.0 获取标注类型 Bean 实例列表
getBeansWithAnnotation(Class<? extends Annontation>)
Spring 3.0 获取指定名称 + 标注类型 Bean 实例
findAnnotationOnBean(String,Class<? extends Annotation>)
层次性依赖查找
双亲BeanFactory:
getParentBeanFactory()
层次性查找
根据Bean名称查找
基于containsLocalBean
方法实现根据Bean类型查找实例列表
单一类型:BeanFactoryUtils#beanOfType
集合类型:BeanFactoryUtils#beansOfTypeIncludingAncestors
根据Java注解查找名称列表
BeanFactoryUtils#beanNamesForTypeIncludingAncestors
延迟依赖查找
Bean 延迟依赖查找接口
org.springframework.beans.factory.ObjectFactory
org.springframework.beans.factory.ObjectProvider
Spring 5 对Java 8 特性扩展
函数式接口getIfAvailable(Supplier)
ifAvailable(Consumer)
Stream 扩展stream()
安全依赖查找对比
依赖查找类型 | 代表实现 | 是否安全 |
---|---|---|
单一类型查找 | BeanFactory#getBean | 否 |
ObjectFactory#getObject | 否 | |
ObjectProvider#getIfAvailable | 是 | |
集合类型查找 | ListableBeanFactory#getBeansOfType | 是 |
ObjectProvider#stream | 是 |
层次性依赖查找的安全性取决于其扩展的单一或集合类型的BeanFactory接口
内建可查找的依赖
- AbstractApplicationContext 内建可查找的依赖
Bean 名称 | Bean 实例 | 使用场景 |
---|---|---|
environment | Environment 对象 | 外部化配置以及 Profiles |
systemProperties | java.util.Properties对象 | Java 系统属性 |
systemEnvironment | java.util.Map 对象 | 操作系统环境变量 |
messageSource | MessageSource 对象 | 国际化文案 |
lifecycleProcessor | LifecycleProcessor 对象 | Lifecycle Bean 处理器 |
applicationEventMulticaster | ApplicationEventMulticaster 对象 | Spring 事件广播器 |
- 注解驱动 Spring 应用上下文内建可查找的依赖
Bean 名称 | Bean 实例 | 使用场景 |
---|---|---|
org.springframework.context.annotation.internalConfigurationAnnotationProcessor | ConfigurationClassPostProcessor 对象 | 处理 Spring 配置类 |
org.springframework.context.annotation.internalAutowiredAnnotationProcessor | AutowiredAnnotationBeanPostProcessor 对象 | 处理 @Autowired 以及 @Value 注解 |
org.springframework.context.annotation.internalCommonAnnotationProcessor | CommonAnnotationBeanPostProcessor 对象 | (条件激活)处理JSR-250注解,如 @PostConstruct 等 |
org.springframework.context.event.internalEventListenerProcessor | EventListenerMethodProcessor 对象 | 处理标注@EventListener 的Spring 事件监听方法 |
org.springframework.context.event.internalEventListenerFactory | DefaultEventListenerFactory 对象 | @EventListener事件监听方法适配为ApplicationListener |
org.springframework.context.annotation.internalPersistenceAnnotationProcessor | PersistenceAnnotationBeanPostProcessor 对象 | (条件激活)处理 JPA 注解场景 |
依赖查找中的经典异常
- BeansException 子类型
异常类型 | 触发条件(举例) | 场景举例 |
---|---|---|
NoSuchBeanDefinitionException | 当查找Bean不存在于IoC容器时 | BeanFactory#getBean ObjectFactory#getObject |
NoUniqueBeanDefinitionException | 类型依赖查找时,IoC容器存在多个Bean实例 | BeanFactory#getBean(Class) |
BeanInstantiationException | 当Bean 所对应的类型非具体类时 | BeanFactory#getBean |
BeanCreationException | 当 Bean 初始化过程中 | Bean初始化方法执行异常 |
BeanDefinitionStoreException | 当BeanDefinition配置元信息非法时 | XML 配置资源无法打开时 |
ObjectFactory 与 BeanFactory 的区别?
ObjectFactory 与 BeanFactory 均提供依赖查找的能力
不过 ObjectFactory 仅关注一个或一种类型的 Bean 依赖查找,并且自身不具备依赖查找的能力,能力则由 BeanFactory 输出
BeanFactory 则提供了单一类型、集合类型以及层次性等多种依赖查找方式
BeanFactory.getBean 操作是否线程安全?
BeanFactory.getBean 方法的执行是线程安全的,超过过程中会增加互斥锁
依赖注入的模式和类型
手动模式 - 配置或者编程的方式,提前安排注入规则
XML 资源配置元信息
Java 注解配置元信息
API配置元信息自动模式 - 实现方提供依赖自动关联的方式,按照内建的注入规则
Autowiring(自动绑定)
依赖注入类型 | 配置元数据举例 |
---|---|
Setter 方法 | <property name="user" ref="userBean"/> |
构造器 | <constructor-arg name="user" ref="userBean"/> |
字段 | @Autowired User user; |
方法 | @Autowired public void user(User user){...} |
接口回调 | class MyBean implements BeanFactoryAware{....} |
自动绑定(Autowiring)
官方说明:
The Spring container can autowire relationships between collaborating beans. You can let Spring resolve collaborators (other beans) automatically for your bean by inspecting the contents of the ApplicationContext.
(Spring容器可以自动连接协作bean之间的关系。通过检查ApplicationContext的内容,您可以让Spring自动地为您的bean解析协作者(其他bean))优点:
• Autowiring can significantly reduce the need to specify properties or constructor arguments.
• Autowiring can update a configuration as your objects evolve.
(•自动装配可以显著减少指定属性或构造函数参数的需要
•自动装配可以随着对象的演进更新配置)
自动绑定(Autowiring)模式
- Autowiring modes
模式 | 说明 |
---|---|
no | 默认值,未激活Autowiring,需要手动指定依赖注入对象 |
byName | 根据被注入属性的名称作为Bean名称进行依赖查找,并将对象设置到该属性 |
byType | 根据被注入属性的类型作为依赖类型进行查找,并将对象设置到该属性 |
constructor | 特殊 byType 类型,用于构造器参数 |
- 限制和不足
Setter 方法注入
实现方式
手动模式
XML资源配置元信息
Java 注解配置元信息
API配置元信息自动模式
byName
byType
构造器注入
实现方式
手动模式
XML 资源配置元信息
Java 注解配置元信息
API 配置元信息自动模式
constructor
字段注入
实现方式
- 手动模式
Java 注解配置元信息
@Autowired
@Resource
@Inject(可选)
方法注入
实现方式
- 手动模式
Java 注解配置元信息
@Autowired
@Resource
@Inject(可选)
@Bean
接口回调注入
Aware 系列接口回调
- 自动模式
内建接口 | 说明 |
---|---|
BeanFactoryAware | 获取IoC容器 - BeanFactory |
ApplicationContextAware | 获取Spring 应用上下文 - ApplicationContext 对象 |
EnvironmentAware | 获取 Environment 对象 |
ResourceLoaderAware | 获取资源加载器对象 - ResourceLoader |
BeanClassLoaderAware | 获取加载当前 Bean Class 的ClassLoader |
BeanNameAware | 获取当前Bean的名称 |
MessageSourceAware | 获取MessageSource对象,用于Spring 国际化 |
ApplicationEventPublisherAware | 获取ApplicationEventPublishAware对象,用于Spring 事件 |
EmbeddedValueResolverAware | 获取StringValueResolver对象,用于占位符处理 |
依赖注入类型选择
- 注入选型
低依赖:构造器注入
多依赖:Setter 方法注入
便利性:字段注入
声明类:方法注入
基础类型注入
原生类型(Primitive):boolean、byte、char、short、int、float、long、double
标量类型(Scalar):Number、Character、Boolean、Enum、Locale、Charset、Currency、Properties、UUID
常规类型(General):Object、String、TimeZone、Calendar、Optional等
Spring 类型:Resource、InputSource、Formatter等
集合类型注入
数组类型(Array):原生类型、标量类型、常规类型、Spring类型
集合类型(Collection)
Collection:List、Set(SortedSet、NavigableSet、EnumSet)
Map:Properties
限定注入
使用注解 @Qualifier 限定
通过 Bean 名称限定
通过分组限定基于注解@Qualifier 扩展限定
自定义注解 - 如 Spring Cloud @LoadBalanced
延迟依赖注入
使用 API ObjectFactory 延迟注入
单一类型
集合类型使用API ObjectProvider 延迟注入(推荐)
单一类型
集合类型
依赖处理过程
入口 -
DefaultListableBeanFactory#resolveDependency
依赖描述符 -
DependencyDescriptor
自动绑定候选对象处理器 -
AutowireCandidateResolver
@Autowired
注入
@Autowired 注入规则
非静态字段
非静态方法
构造器
@Autowired 注入过程
元信息解析
依赖查找
依赖注入(字段、方法)
@Inject
注入
@Inject 注入过程
如果 JSR-330 存在于 ClassPath 中,复用AutowiredAnnotationBeanPostProcessor
实现
Java 通用注解注入原理
CommonAnnotationBeanPostProcessor
- 注入注解
javax.xml.ws.WebSerivceRef
javax.ejb.EJB
javax.annotation.Resource
- 生命周期注解
javax.annotation.PostConstruct
javax.annotation.PreDestroy
自定义依赖注入注解
- 基于
AutowiredAnnotationBeanPostProcesser
实现 - 自定义实现
生命周期处理
InstantiationAwareBeanPostProcessor
MergedBeanDefinitionPostProcessor
元数据
InjectedElement
InjectionMetadata
有多少种依赖注入的方式?
构造器注入、Setter 注入、字段注入、方法注入、接口回调注入
你偏好构造器注入还是Setter 注入?
两种依赖注入的方式均可使用,如果是必须依赖的话,那么推荐使用构造器注入,Setter 注入用于可选依赖
Spring 依赖注入的来源有哪些?
Spring BeanDefinition、单体对象、Resolvable Dependency、@Value 外部化配置
依赖查找的来源
- 查找来源
来源 | 配置元数据 |
---|---|
Spring BeanDefinition | <bean id="user" class="org.vincent.User"/> |
@Bean public User user(){....} | |
BeanDefinitionBuilder | |
单体对象 | API 实现 |
- Spring 内建 BeanDefinition
Bean 名称 | Bean 实例 | 使用场景 |
---|---|---|
org.springframework.context.annotation.internalConfigurationAnnotationProcessor | ConfigurationClassPostProcessor对象 | 处理Spring 配置类 |
org.springframework.context.annotation.internalAutowiredAnnotationProcessor | AutowiredAnnotationBeanPostProcessor 对象 | 处理@Autowired 以及@Value注解 |
org.springframework.context.annotation.internalCommonAnnotationProcessor | CommonAnnotationBeanPostProcessor对象 | (条件激活)处理JSR-250注解,如 @PostConstruct 等 |
org.springframework.context.internalEventListenerProcessor | EventListenerMethodProcessor 对象 | 处理标注@EventListener的Spring 事件监听方法 |
- Spring 内建单例对象
Bean 名称 | Bean 实例 | 使用场景 |
---|---|---|
environment | Environment 对象 | 外部化配置以及 Profiles |
systemProperties | java.util.Properties 对象 | Java 系统属性 |
systemEnvironment | java.util.Map 对象 | 操作系统环境变量 |
messageSource | MessageSource 对象 | 国际化文案 |
lifecycleProcessor | LifecycleProcessor 对象 | Lifecycle Bean 处理器 |
applicationEventMulticaster | ApplicationEventMulticaster 对象 | Spring 事件广播器 |
依赖注入的来源
- 注入来源
来源 | 配置元数据 |
---|---|
Spring BeanDefinition | <bean id="user" class="org.vincent.User"/> |
@Bean public User user(){....} | |
BeanDefinitionBuilder | |
单例对象 | API实现 |
非 Spring 容器管理对象 |
Spring 容器管理和游离对象
- 依赖对象
来源 | Spring Bean 对象 | 生命周期管理 | 配置元信息 | 使用场景 |
---|---|---|---|---|
Spring BeanDefinition | 是 | 是 | 有 | 依赖查找、依赖注入 |
单体对象 | 是 | 否 | 无 | 依赖查找、依赖注入 |
Resolvable Dependency | 否 | 否 | 无 | 依赖注入 |
Spring BeanDefinition 作为依赖来源
- 元素
1、元数据:BeanDefinition
2、注册:BeanDefinitionRegistry#registerBeanDefinition
3、类型:延迟和非延迟
4、顺序:Bean 生命周期顺序按照注册顺序
单例对象作为依赖来源
要素
来源:外部普通Java对象(不一定是POJO)
注册:SingletonBeanRegistry#registerSingleton限制
无生命周期管理
无法实现延迟初始化Bean
非Spring 容器管理对象作为依赖来源
要素
注册:ConfigurableListableBeanFactory#registerResolvableDependency限制
无生命周期管理
无法实现延迟初始化Bean
无法通过依赖查找
外部化配置作为依赖来源
要素
类型:非常规 Spring 对象依赖来源限制
无生命周期管理
无法实现延迟初始化Bean
无法通过依赖查找
注入和查找的依赖来源是否相同?
否,依赖查找的来源仅限于Spring BeanDefinition 以及单例对象,而依赖注入的来源还包括Resolvable Dependency以及 @Value 所标注的外部化配置
单例对象能在IoC容器启动后注册吗?
可以的,单例对象的注册与BeanDefinition 不同,
BeanDefinition
会被ConfinurableListableBeanFactory#freezeConfiguration()
方法影响,从而冻结注册,单例对象则没有这个限制
Spring Bean 作用域
来源 | 说明 |
---|---|
singleton | 默认Spring Bean作用域,一个BeanFactory 有且仅有一个实例 |
prototype | 原型作用域,每次依赖查找和依赖注入生成新 Bean 对象 |
request | 将 Spring Bean 存储在 ServletRequest 上下文中 |
session | 将 Spring Bean 存储在 HttpSession 中 |
application | 将 Spring Bean 存储在 ServletContext 中 |
“singleton” Bean 作用域
“prototype” Bean 作用域
- 注意事项
Spring 容器没有办法管理
prototype Bean
的完整生命周期,也没有办法记录示例的存在。销毁回调方法将不会执行,可以利用BeanPostProcessor
进行清扫工作
"request" Bean 作用域
配置
XML -<bean class= "..." scope = "request" />
Java 注解 -@RequestScope 或 @Scope (WebApplicationContext.SCOPE_REQUEST)
实现
API -RequestScope
"session" Bean 作用域
配置
XML - <bean class= "..." scope = "session" />
Java注解 - @RequestScope 或 @Scope (WebApplication.SCOPE_SESSION)实现
API - SessionScope
"application" Bean 作用域
配置
XML - <bean class= "..." scope = "application" />
Java 注解 - @ApplicationScope 或 @Scope(WebApplicationContext.SCOPE_APPLICATION)实现
API - ApplicationScope
自定义 Bean 作用域
实现Scope
org.springframework.beans.factory.config.Scope注册Scope
API - org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope
配置<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="..."> </entry> </map> </property> </bean>
Spring 内建的Bean 作用域有几种?
singleton 、prototype、request、session、application 以及 websocket
singleton Bean 是否在一个应用是唯一的?
否,singleton bean 仅在当前Spring IoC 容器(BeanFactory)中是单例对象
“application” Bean 是否被其他方案替代?
可以的,实际上,“application” Bean 与 “singleton” Bean 没有本质区别
Spring Bean 元信息配置阶段
- BeanDefinition 配置
1、面向资源
XML 配置
Properties 资源配置2、面向注解
3、面向API
Spring Bean 元信息解析阶段
面向资源BeanDefinition 解析
BeanDefinitionReader
XML解析器 - BeanDefinitionParser面向注解BeanDefinition 解析
AnnotatedBeanDefinitionReader
Spring Bean 注册阶段
- BeanDefinition 注册接口
BeanDefinitionRegistry
Spring BeanDefinition 合并阶段
- BeanDefinition 合并
父子BeanDefinition 合并
1、当前BeanFactory 查找
2、层次性BeanFactory查找
Spring Bean Class 加载阶段
ClassLoader 类加载
Java Security 安全控制
ConfigurableBeanFactory 临时 ClassLoader
Spring Bean 实例化阶段
实例化方式
传统实例化方式
实例化策略 - InstantiationStrategy构造器依赖注入
Spring Bean 实例化前阶段
- 非主流生命周期 - Bean 实例化前阶段
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
Spring Bean 实例化后阶段
- Bean 属性赋值(Populate) 判断
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
Spring Bean 属性赋值前阶段
Bean 属性值元信息
PropertyValuesBean 属性赋值前回调
Spring 1.2 - 5.0:InstantiationAwareBeanPostProcessor#postProcessPropertyValues
Spring 5.1:InstantiationAwareBeanPostProcessor#postProcessProperties
Spring Bean Aware 接口回调阶段
Spring Aware接口
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
- EnvironmentAware
- EmbeddedValueResolverAware
- ResourceLoaderAware
- ApplicationEventPublisherAware
- MessageSourceAware
- ApplicationContextAware
Spring Bean 初始化前阶段
已完成
Bean 实例化
Bean 属性赋值
Bean Aware 接口回调方法回调
BeanPostProcessor#postProcessBeforeInitialization
Spring Bean 初始化阶段
Bean 初始化(Initialization)
@PostConstruct 标注方法
实现InitializingBean 接口的 afterPropertiesSet() 方法
自定义初始化方法
Spring Bean 初始化后阶段
- 方法回调
BeanPostProcessor#postProcessAfterInitialization
Spring Bean 初始化完成阶段
- 方法回调
Spring 4.1 +:SmartInitializingSingleton#afterSingletonsInstantiated
Spring Bean 销毁前阶段
- 方法回调
DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
Spring Bean 销毁阶段
Bean 销毁(Destroy)
@PreDestroy 标注方法
实现DisposableBean 接口的destroy() 方法
自定义销毁方法
Spring Bean 垃圾收集
Bean 垃圾回收(GC)
关闭Spring 容器(应用上下文)
执行GC
Spring Bean 覆盖的finalize() 方法被回调
BeanPostProcessor 的使用场景有哪些?
BeanPostProcessor 提供Spring Bean 初始化前和初始化后的生命周期回调,分别对应
postProcessBeforeInitialization
以及postProcessAfterInitialization
方法,允许对关心的Bean 进行扩展,甚至是替换。
其中,ApplicationContext 相关的Aware 回调也是基于BeanPostProcessor 实现,即ApplicationContextAwareProcessor
BeanFactoryPostProcessor 与 BeanPostProcessor 的区别?
BeanFactoryPostProcessor
是Spring BeanFactory
(实际为ConfigurableListableBeanFactory
)的后置处理器,用于扩展BeanFactory,或通过BeanFactory进行依赖查找和依赖注入
BeanFactoryPostProcessor
必须有Spring ApplicationContext
执行,BeanFactory
无法与其直接交互而BeanPostProcessor 则直接与BeanFactory 关联,属于N 对 1 的关系
BeanFactory 是怎样处理Bean生命周期?
BeanFactory
的默认实现为:DefaultListableBeanFactory
,其中Bean生命周期与方法映射如下:
- BeanDefinition 注册阶段 - registerBeanDefinition
- BeanDefinition 合并阶段 - getMergedBeanDefinition
- Bean 实例化前阶段 - resolveBeforeInstantiation
- Bean 实例化阶段 - createBeanInstance
- Bean 实例化后阶段 - populateBean
- Bean 属性赋值前阶段 - populateBean
- Bean 属性赋值阶段 - populateBean
- Bean Aware 接口回调阶段 - initializeBean
- Bean 初始化前阶段 - initializeBean
- Bean 初始化阶段 - initializeBean
- Bean 初始化后阶段 - initializeBean
- Bean 初始化完成阶段 - preInstantiateSingletons
- Bean 销毁前阶段 - destroyBean
- Bean 销毁阶段 - destroyBean
Spring 配置元信息
Spring Bean 配置元信息 -
BeanDefinition
Spring Bean 属性元信息 -
PropertyValues
Spring 容器配置元信息
Spring 外部化配置元信息 -
PropertySource
Spring Profile 元信息 -
@Profile
Spring Bean 配置元信息
Bean配置元信息 - BeanDefinition
GenericBeanDefinition
:通用类 BeanDefinition
RootBeanDefinititon
:无Parent的BeanDefinition 或者合并后 BeanDefinition
AnnotatedBeanDefinition
:注解标注的BeanDefinition
Spring Bean 属性元信息
Bean 属性元信息 -
PropertyValues
可修改实现 -MutablePropertyValues
元素成员 -PropertyValue
Bean 属性上下文存储 -
AttributeAccessor
Bean 元信息元素 -
BeanMetadataElement
Spring 容器配置元信息
- Spring XML 配置元信息 - beans 元素相关
Bean 元素属性 | 默认值 | 使用场景 |
---|---|---|
profile | null(留空) | Spring Profile 配置值 |
default-lazy-init | default | 当 outter beans "default-lazy-init" 属性存在时,继承该值,否则为"false" |
default-merge | default | 当 outter beans "default-merge" 属性存在时,继承该值,否则为"false" |
default-autowire | default | 当 outter beans "default-autowire" 属性存在时,继承该值,否则为"no" |
default-autowire-candidates | null(留空) | 默认Spring Beans 名称 pattern |
default-init-method | null(留空) | 默认Spring Beans 自定义初始化方法 |
default-destroy-method | null(留空) | 默认Spring Beans 自定义销毁方法 |
- Spring XML 配置元信息 - 应用上下文相关
XML 元素 | 使用场景 |
---|---|
<context:annotation-config/> | 激活 Spring 注解驱动 |
<context:component-scan/> | Spring @Component 以及自定义注解扫描 |
<context:load-time-weaver/> | 激活 Spring LoadTimeWeaver |
<context:mbean-export/> | 暴露 Spring Beans 作为 JMX Beans |
<context:mbean-server/> | 将当前平台作为 MBeanServer |
<context:property-placeholder/> | 加载外部化配置资源作为 Spring 属性配置 |
<context:property-override/> | 利用外部化配置资源覆盖Spring 属性值 |
基于 XML 资源装载Spring Bean 配置元信息
- Spring Bean 配置元信息(底层实现 - XmlBeanDefinitionReader)
XML 元素 | 使用场景 |
---|---|
<beans:beans/> | 单 XML 资源下的多个Spring Beans 配置 |
<beans:bean/> | 单个Spring Bean 定义 (BeanDefinition)配置 |
<beans:alias/> | 为 Spring Bean 定义 (BeanDefinition)映射别名 |
<beans:import/> | 加载外部Spring XML 配置资源 |
基于Properties 资源装载Spring Bean 配置元信息
- Spring Bean 配置元信息(底层实现 - PropertiesBeanDefinitionReader)
Properties 属性名 | 使用场景 |
---|---|
(class) | Bean 类全称限定名 |
(abstract) | 是否为抽象的 BeanDefinition |
(parent) | 指定parent BeanDefinition 名称 |
(lazy-init) | 是否为延迟初始化 |
(ref) | 引用其他 Bean 的名称 |
(scope) | 设置 Bean 的 scope 属性 |
${n} | n 表示第 n + 1 个构造器参数 |
基于Java 注解装载Spring Bean 配置元信息
- Spring 模式注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Repository | 数据仓储模式注解 | 2.0 |
@Component | 通用组件模式注解 | 2.5 |
@Service | 服务模式注解 | 2.5 |
@Controller | Web 控制器模式注解 | 2.5 |
@Configuration | 配置类模式注解 | 3.0 |
- Spring Bean 定义注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Bean | 替换 XML 元素<bean> | 3.0 |
@DependsOn | 替换 XML 属性 <bean depends-on="..."/> | 3.0 |
@Lazy | 替换 XML 属性 <bean lazy-init="true|false"/> | 3.0 |
@Primary | 替换 XML 元素 <bean primary="true|false"/> | 3.0 |
@Role | 替换 XML 元素 <bean role="..."/> | 3.1 |
@Lookup | 替换 XML 元素 <bean lookup-method="..."/> | 4.1 |
- Spring Bean 依赖注入注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Autowired | Bean 依赖注入,支持多种依赖查找方式 | 2.5 |
@Qualifier | 细粒度的@Autowired 依赖查找 | 2.5 |
- Spring Bean 生命周期回调注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@PostConstruct | 替换 XML 元素 <bean init-method="...."> 或 initializingBean | 2.5 |
@PreDestroy | 替换 XML 元素 <bean destroy-method="...."/> 或 DisposableBean | 2.5 |
Spring Bean 配置元信息底层实现
- Spring BeanDefinition 解析与注册
实现场景 | 实现类 | 起始版本 |
---|---|---|
XML 资源 | XmlBeanDefinitionReader | 1.0 |
Properties 资源 | PropertiesBeanDefinitionReader | 1.0 |
Java 注解 | AnnotationBeanDefinitionReader | 3.0 |
- Spring XML 资源 BeanDefinition 解析与注册
核心 API -
XmlBeanDefinitionReader
1、资源 -Resource
2、底层 -BeanDefinitionDocumentReader
2.1、XML解析 -Java DOM Level 3 API
2.2、BeanDefinition 解析 -BeanDefinitionParserDelegate
2.3、BeanDefinition 注册 -BeanDefinitionRegistry
- Spring Properties 资源BeanDefinition 解析与注册
核心 API -
PropertiesBeanDefinitionReader
1、资源
1.1、字节流 -Resource
1.2、字符流 -EncodedResource
2、底层
2.1、存储 -java.util.Properties
2.2、BeanDefinition 解析 - API 内部实现
2.3、BeanDefinition 注册 -BeanDefinitionRegistry
- Spring Java 注解 BeanDefinition 解析与注册
核心 API - AnnotatedBeanDefinitionReader
1、资源
1.1、类对象 -java.lang.Class
2、底层
2.1、条件评估 -ConditionEvaluator
2.2、Bean 范围解析 -ScopeMetadataResolver
2.3、BeanDefinition 解析 - 内部 API 实现
2.4、BeanDefinition 处理 -AnnotationConfigUtils.processCommonDefinitionAnnotations
2.5、BeanDefinition 注册 - BeanDefinitionRegistry
基于 XML 资源装载 Spring IoC 容器配置元信息
- Spring IoC 容器相关XML配置
命名空间 | 所属模块 | Schema 资源 URL |
---|---|---|
beans | spring-beans | https://www.springframework.org/schema/beans/spring-beans.xsd |
context | spring-context | https://www.springframework.org/schema/context/spring-context.xsd |
aop | spring-aop | https://www.springframework.org/schema/aop/spring-aop.xsd |
tx | spring-tx | https://www.springframework.org/schema/tx/spring-tx.xsd |
util | spring-beans | https://www.springframework.org/schema/util/spring-util.xsd |
tool | spring-beans | https://www.springframework.org/schema/tool/spring-tool.xsd |
基于 Java 注解装载Spring IoC 容器配置元信息
- Spring IoC 容器装配注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@ImportResource | 替换 XML 元素 <import> | 3.0 |
@Import | 导入Configuration Class | 3.0 |
@ComponentScan | 扫描指定 package 下标注 Spring 模式注解的类 | 3.1 |
- Spring IoC 配置属性注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@PropertySource | 配置属性抽象 PropertySource 注解 | 3.1 |
@PorpertySources | @PropertySource 集合注解 | 4.0 |
基于Extensible XML authoring 扩展 Spring XML 元素
Spring XML 扩展
编写XML Schema 文件:定义XML结构
自定义
NamespaceHandler
实现:命名空间绑定自定义
BeanDefinitionParser
实现:XML元素与BeanDefinition 解析注册XML扩展:命名空间与
XML Schema
映射
Extensible XML authoring 扩展原理
- 核心流程
BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element,BeanDefinition)
1、 获取 namespace
2、通过 namespace 解析 NamespaceHandler
3、构造 ParserContext
4、解析元素,获取 BeanDefinition
基于 Properties 资源装载外部化配置
注解驱动
@org.springframework.context.annotation.PropertySource
@org.springframework.context.annotation.PropertySources
API 编程
org.springframework.core.env.PropertySource
org.springframework.core.env.PropertySources
基于YAML 资源装载外部化配置
Spring 配置元信息具体有哪些?
Bean 配置元信息:通过媒介(如XML、Properties等),解析
BeanDefinition
IoC 容器配置元信息:通过媒介(如XML、Properties等),控制IoC 容器行为,比如注解驱动、AOP等
外部化配置:通过资源抽象(如Properties、YAML等),控制
PropertySource
Spring Profile:通过外部化配置,提供条件分支流程
Extensible XML authoring 的缺点?
高度复杂:开发人员需要熟悉XML Schema、spring.handlers、spring.shemas 以及Spring API
嵌套元素支持较弱:通常需要使用方法递归或者嵌套解析的方式处理嵌套(子)元素
XML 处理性能较差:Spring XML 基于DOM Level 3 API 实现,该 API 便于理解,然而性能较差
XML框架移植性较差:很难适配高性能和便利性的XML 框架,如JAXB
Spring 资源管理引入动机
为什么 Spring 不使用 Java 标准资源管理,而选择重新发明轮子?
Java 标准资源管理强大,然而扩展复杂,资源存储方式并不统一
Spring 要自立门户
Spring “抄”、“超”、“潮”
Java 标准资源管理
- Java 标准资源定位
职责 | 说明 |
---|---|
面向资源 | 文件系统、artifact(jar 、war 、ear 文件)以及远程资源(HTTP、FTP等) |
API 整合 | java.lang.ClassLoader#getResource、java.io.File 或 java.net.URL |
资源定位 | java.net.URL 或 java.net.URI |
面向流式存储 | java.net.URLConnection |
协议扩展 | java.net.URLStreamHandler 或 java.net.URLStreamHandlerFactory |
- Java URL 协议扩展
基于
java.net.URLStreamHandlerFactory
基于
java.net.URLStreamHandler
- 基于 java.net.URLStreamHandlerFactory 扩展协议
- 基于 java.net.URLStreamHandler 扩展协议
JDK1.8 内建协议实现
协议 | 实现类 |
---|---|
file | sun.net.www.protocol.file.Handler |
ftp | sun.net.www.protocol.ftp.Handler |
http | sun.net.www.protocol.http.Handler |
https | sun.net.www.protocol.https.Handler |
jar | sun.net.www.protocol.jar.Handler |
mailto | sun.net.www.protocol.mailto.Handler |
netdoc | sun.net.www.protocol.netdoc.Handler |
实现类名必须为“Handler”
实现类命名规则 | 说明 |
---|---|
默认 | sun.net.www.protocol.${protocol}.Handler |
自定义 | 通过Java Properties java.protocol.handler.pkgs 指定实现类包名,实现类名必须为“Handler”,如果存在多包名指定,通过分隔符 “|” |
Spring 资源接口
- 资源接口
类型 | 接口 |
---|---|
输入流 | org.springframework.core.io.InputStreamSource |
只读资源 | org.springframework.core.io.Resource |
可写资源 | org.springframework.core.io.WritableResource |
资源编码 | org.springframework.core.io.support.EncodedResource |
上下文资源 | org.springframework.core.io.ContextResource |
Spring 内建 Resource 实现
- 内建实现
资源来源 | 资源协议 | 实现类 |
---|---|---|
Bean定义 | 无 | org.springframework.beans.factory.support.BeanDefinitionResource |
数组 | 无 | org.springframework.core.io.ByteArrayResource |
类路径 | classpath:/ | org.springframework.core.io.ClassPathResource |
文件系统 | file:/ | org.springframework.core.io.UrlResource |
URL | URL 支持的协议 | org.springframework.core.io.UrlResource |
ServletContext | 无 | org.springframework.web.context.support.ServletContextResource |
Spring Resource 接口扩展
- 可写资源接口
org.springframework.core.io.WritableResource
org.springframework.core.io.FileSystemResource
org.springframework.core.io.FileUrlResource(@since 5.0.2)
org.springframework.core.io.PathResource(@since 4.0 & @Deprecated)
- 编码资源接口
org.springframework.core.io.support.EncodedResource
Spring 资源加载器
- Resource 加载器
org.springframework.core.io.ResourceLoader
org.springframework.core.io.DefaultResourceLoader
org.springframework.core.io.FileSystemResourceLoader
org.springframework.core.io.ClassRelativeResourceLoader
org.springframework.context.support.AbstractApplicationContext
Spring 通配路径资源加载器
- 通配路径 ResourceLoader
org.springframework.core.io.support.ResourcePatternResolver
org.springframework.core.io.support.PathMatchingResourcePatternResolver
- 路径匹配器
org.springframework.util.PathMatcher
Ant模式匹配实现 -org.springframework.util.AntPathMatcher
Spring 通配路径资源扩展
- 实现
org.springframework.util.PathMatcher
- 重置PathMatcher
PathMatchingResourcePatternResolver#setPathMatcher
依赖注入 Spring Resource
- 基于@Value 实现
如:
@Value("classpath:/...")
private Resource resource;
依赖注入ResourceLoader
方法一:实现ResourceLoaderAware 回调
方法二:@Autowired 注入 ResourceLoader
方法三:注入ApplicationContext 作为 ResourceLoader
Spring 配置资源中有哪些常见类型?
- XML 资源
- Properties 资源
- YAML 资源
请列举不同类型 Spring 配置资源?
- XML 资源
普通Bean Definition XML 配置资源 -.xml
Spring Schema 资源 -.xsd
- Properties 资源
普通Properties 格式资源 -*.properties
Spring Handler 实现类映射文件 - META-INF/spring.handlers
Spring Schema 资源映射文件 - META-INF/spring.schemas
- YAML 资源
普通YAML 资源配置 -*.yaml 或 *.yml
Java 标准资源管理扩展的步骤?
简易实现
实现URLStreamHandler 并放置在sun.net.www.protocol.${protocol}.Handler 包下自定义实现
实现 URLStreamHandler
添加 -Djava.protocol.handler.pkgs 启动参数,指向URLStreamHandler 实现类的包下高级实现
实现URLStreamHandlerFactory并传递到URL之中
Spring 国际化使用场景
普通国际化文案
Bean Validation 校验国际化文案
Web 站点页面渲染
Web MVC 错误消息提示
Spring 国际化接口
核心接口
org.springframework.context.MessageSource
主要概念
文案模板编码(code)
文案模板参数(args)
区域(Locale)
层次性 MessageSource
- Spring层次性接口
org.springframework.beans.factory.HierarchicalBeanFactory
org.springframework.context.ApplicationContext
org.springframework.beans.factory.config.BeanDefinition
- Spring 层次性国际化接口
org.springframework.context.HierarchicalMessageSource
Java国际化标准实现
- 核心接口
抽象实现 - java.util.ResourceBundle
Properties 资源实现 - java.util.PropertyResourceBundle
举例实现 - java.util.ListResourceBundle
- ResourceBundle 核心特性
Key - Value 设计
层次性设计
缓存设计
字符编码控制 - java.util.ResourceBundle.Control(@since 1.6)
Control SPI 扩展 - java.util.spi.ResourceBundleControlProvider(@since 1.8)
Java 文件格式化
- 核心接口
java.text.MessageFormat
- 基本用法
设置消息格式模式 - new MessageFormat(...)
格式化 - format(new Object[]{...})
- 消息格式模式
格式元素:{ArgumentIndex(,FormatType,(FormatStyle))}
FormatType:消息格式类型,可选项,每种类型在number、date、time 和 choice 类型选其一
FormatStyle:消息格式风格,可选项,包括:short、medium、long、full、integer、currency、percent
- 高级特性
重置消息格式模式
重置java.util.Locale
重置java.text.Format
MessageSource 开箱即用实现
基于ResourceBundle + MessageFormat 组合 MessageSource 实现
org.springframework.context.support.ResourceBundleMessageSource
可重载Properties + MessageFormat 组合 MessageSource 实现
org.springframework.context.support.ReloadableResourceBundleMessageSource
MessageSource 内建依赖
- MessageSource 内建Bean 可能来源
预注册 Bean 名称为:"messageSource",类型为:MessageSource Bean
- 默认内建实现 - DelegatingMessageSource
层次性查找 MessageSource 对象
Spring Boot 为什么要新建MessageSource Bean?
AbstractApplicationContext 的实现决定了MessageSource 内建实现
Spring Boot 通过外部化配置简化 MessageSource Bean 构建
Spring Boot 基于 Bean Validation 校验非常普遍
Spring 国际化接口有哪些?
- 核心接口 -
MessageSource
- 层次性接口 -
org.springframework.context.HierarchicalMessageSource
Spring 有哪些MessageSource 内建实现?
org.springframework.context.support.ResourceBundleMessageSource
org.springframework.context.support.ReloadableResourceBundleMessageSource
org.springframework.context.support.StaticMessageSource
org.springframework.context.support.DelegatingMessageSource
如何实现配置自动更新MessageSource?
Java NIO 2:java.nio.file.WatchService
Java Concurrency:java.util.concurrent.ExecutorService
Spring:org.springframework.context.support.AbstractMessageSource
Spring 校验使用场景
Spring 常规校验(Validator)
Spring 数据绑定(DataBinder)
Spring Web 参数绑定(WebDataBinder)
Spring Web MVC / Spring WebFlux 处理方法参数校验
Validator 接口设计
接口职责
Spring 内部校验器接口,通过编程的方式校验目标对象核心方法
supports(Class)
:校验目标类能否校验validate(Object,Errors)
:校验目标对象,并将校验失败的内容输出至Errors对象配套组件
错误收集器:org.springframework.validation.Errors
Validator工具类:org.springframework.validation.ValidationUtils
Errors 接口设计
接口职责
数据绑定和校验错误收集接口,与Java Bean 和其属性有强关联性核心方法
reject
方法(重载):收集错误文案rejectValue
方法(重载):收集对象字段中的错误文案配套组件
Java Bean 错误描述:org.springframework.validation.ObjectError
Java Bean 属性错误描述:org.springframework.validation.FieldError
Errors 文案来源
Errors 文案生成步骤
选择Errors实现(如:
org.springframework.validation.BeanPropertyBindingResult
)调用
reject
或rejectValue
方法获取
Errors
对象中ObjectError
或FieldError
将ObjectError 或 FieldError 中的
code
和args
,关联MessageSource
实现(如:ResourceBundleMessageSource
)
自定义Validator
实现org.springframework.validation.Validator 接口
实现 supports 方法
实现 validate 方法
通过Errors 对象收集错误
ObjectError:对象(Bean)错误
FieldError:对象(Bean)属性(Property)错误通过ObjectError 和 FieldError 关联 MessageSource 实现获取最终文案
Validator 的救赎
Bean Validation 和 Validator 适配
核心组件 -
org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
依赖
Bean Validation
-JSR-303 or JSR-349 provider
Bean 方法参数校验 -
org.springframework.validation.beanvalidation.MethodValidationPostProcessor
Spring 校验接口是哪个?
org.springframework.validation.Validator
Spring 有哪些校验核心组件?
校验器:
org.springframework.validation.Validator
错误收集器:
org.springframework.validation.Errors
Java Bean 错误描述:
org.springframework.validation.ObjectError
Java Bean 属性错误描述:
org.springframework.validation.FieldError
Bean Validation 适配:
org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
Spring 数据绑定使用场景
Spring BeanDefinition 到 Bean 实例创建
Spring 数据绑定(DataBinder)
Spring Web 参数绑定(WebDataBinder)
Spring 数据绑定组件
- 标准组件
org.springframework.validation.DataBinder
- Web 组件
org.springframework.web.bind.WebDataBinder
org.springframework.web.bind.ServletRequestDataBinder
org.springframework.web.bind.support.WebRequestDataBinder
org.springframework.web.bind.support.WebExchangeDataBinder(since 5.0)
Spring 数据绑定组件
- DataBinder 核心属性
属性 | 说明 |
---|---|
target | 关联目标 Bean |
objectName | 目标Bean名称 |
bindingResult | 属性绑定结果 |
typeConverter | 类型转换器 |
conversionService | 类型转换服务 |
messageCodesResolver | 校验错误文案Code处理器 |
validators | 关联的Bean Validator 实例集合 |
- DataBinder 绑定方法
bind(PropertyValues):将PropertyValues Key - Value 内容映射到关联Bean(target)中的属性上
假设PropertyValues 中包含“name = vincent” 的键值对,同时Bean对象User 中存在name 属性,当bind 方法执行时,User对象中的 name 属性值将被绑定为“vincent”
Spring 数据绑定元数据
- DataBinder 元数据 -
PropertyValues
特征 | 说明 |
---|---|
数据来源 | BeanDefinition,主要来源XML资源配置 BeanDefinition |
数据结构 | 由一个或多个PropertyValue 组成 |
成员结构 | PropertyValue 包含属性名称,以及属性值(包括原始值、类型转换后的值) |
常见实现 | MutablePropertyValues |
Web扩展实现 | ServletConfigPropertyValues、ServletRequestParameterPropertyValues |
相关声明周期 | InstantiationAwareBeanPostProcessor#postProcessProperties |
Spring 数据绑定控制参数
- DataBinder 绑定控制参数
参数名称 | 说明 |
---|---|
ignoreUnknownFields | 是否忽略未知字段,默认值:true |
ignoreInvalidFields | 是否忽略非法字段,默认值:false |
autoGrowNestedPaths | 是否自动增加嵌套路径,默认值:true |
allowedFields | 绑定字段白名单 |
disallowedFields | 绑定字段黑名单 |
requiredFields | 必须绑定字段 |
BeanWrapper 的使用场景
Spring 底层JavaBeans 基础设施的中心化接口
通常不会直接使用,间接用于BeanFactory 和 DataBinder
提供标准JavaBeans 分析和操作,能够单独或批量存储Java Bean 的属性(properties)
支持嵌套属性路径(nested path)
实现类
org.springframework.beans.BeanWrapperImpl
Spring底层Java Beans 替换实现
JavaBeans 核心实现 - java.beans.BeanInfo
属性(Property):java.beans.PropertyEditor
方法(Method)
事件(Event)
表达式(Expression)Spring 替换实现 - org.springframework.beans.BeanWrapper
属性(Property):java.beans.PropertyEditor
嵌套属性路径(nested path)
标准 JavaBeans 是如何操作属性的?
API | 说明 |
---|---|
java.beans.Introspector | JavaBeans 内省 API |
java.beans.BeanInfo | JavaBeans 元信息API |
java.beans.BeanDescriptor | JavaBeans 信息描述符 |
java.beans.PropertyDescriptor | JavaBeans 属性描述符 |
java.beans.MethodDescriptor | JavaBeans 方法描述符 |
java.beans.EventSetDescriptor | JavaBeans 事件集合描述符 |
DataBinder 数据校验
- DataBinder 与 BeanWrapper
bind 方法生成 BeanPropertyBindingResult
BeanPropertyBindingResult 关联 BeanWrapper
Spring 数据绑定API 是什么?
org.springframwork.validation.DataBinder
BeanWrapper 与 JavaBeans 之间关系是?
Spring 底层 JavaBeans 基础设施的中心化接口
Spring 类型转换的实现
基于 JavaBeans 接口的类型转换实现
基于 java.beans.PropertyEditor 接口扩展Spring 3.0+ 通用类型转换实现
使用场景
场景 | 基于JavaBeans 接口的类型转换实现 | Spring 3.0+ 通用类型转换实现 |
---|---|---|
数据绑定 | YES | YES |
BeanWrapper | YES | YES |
Bean 属性类型转换 | YES | YES |
外部化属性类型转换 | NO | YES |
基于 JavaBeans 接口的类型转换
核心职责
将 String 类型的内容转化为目标类型的对象扩展原理
Spring 框架将文本内容传递到PropertyEditor 实现的setAsText(String)方法PropertyEditor#setAsText(String)方法实现将String类型转换为目标类型的对象
将目标类型的对象传入PropertyEditor#setValue(Object) 方法
PropertyEditor#setValue(Object)方法实现需要临时存储传入对象
Spring 框架将通过PropertyEditor#getValue() 获取类型转换后的对象
Spring 内建 PropertyEditor 扩展
- 内建扩展(org.springframework.beans.propertyeditors 包下)
转换场景 | 实现类 |
---|---|
String -> Byte 数组 | org.springframework.beans.propertyeditors.ByteArrayPropertyEditor |
String -> Char | org.springframework.beans.propertyeditors.CharacterEditor |
String -> Char 数组 | org.springframework.beans.propertyeditors.CharArrayPropertyEditor |
String ->Charset | org.springframework.beans.propertyeditors.CharsetEditor |
String -> Class | org.springframework.beans.propertyeditors.ClassEditor |
String -> Currency | org.springframework.beans.propertyeditors.CurrencyEditor |
... | ... |
自定义 PropertyEditor 扩展
扩展模式
扩展java.beans.PropertyEditorSupport 类实现
org.springframework.beans.PropertyEditorRegistrar
实现registerCustomEditors(org.springframework.beans.PropertyEditorRegistry)
方法
将PropertyEditorRegistrar
实现注册为Spring Bean
向
org.springframework.beans.PropertyEditorRegistry
注册自定义PropertyEditor
实现
通用类型实现registerCustomEditor(Class<?>,PropertyEditor)
Java Bean 属性类型实现:registerCustomEditor(Class<?>,String,PropertyEditor)
Spring PropertyEditor 的设计缺陷
违反职责单一原则
java.beans.PropertyEditor 接口职责太多,除了类型转换,还包括Java Beans 事件 和Java GUI 交互java.beans.PropertyEditor 实现类型局限
来源类型只能为java.lang.String 类型java.beans.PropertyEditor 实现缺少类型安全
除了实现类命名可以表达语义,实现类无法感知目标转换类型
Spring 3 通用类型转换接口
类型转换接口-
org.springframework.core.convert.converter.Converter<S,T>
泛型参数S:来源类型,参数T:目标类型
核心方法:T convert(S)通用类型转换接口 -
org.springframework.core.convert.converter.GenericConverter
核心方法:convert(Object,TypeDescriptor,TypeDescriptor)
配对类型:org.springframework.core.convert.converter.GenericConverter.ConvertiblePair
类型描述:org.springframework.core.convert.TypeDescriptor
Spring 内建类型转换器
- 内建扩展
转换场景 | 实现类所在包名(package) |
---|---|
日期/时间相关 | org.springframework.format.datetime |
Java 8 日期 / 时间相关 | org.springframework.format.datetime.standard |
通用实现 | org.springframework.core.convert.support |
Converter 接口的局限性
局限一:缺少Source Type 和 Target Type 前置判断
应对:增加org.springframework.core.converter.ConditionalConverter
实现局限二:仅能转换单一的Source Type 和 Target Type
应对:使用org.springframework.core.convert.converter.GenericConverter
代替
GenericConverter 接口
- org.springframework.core.convert.converter.GenericConverter
核心要素 | 说明 |
---|---|
使用场景 | 用于“复合”类型转换场景,比如Collection、Map、数组等 |
转换范围 | Set<ConvertiblePair> getConvertibleTypes() |
配对类型 | org.springframework.core.convert.converter.GenericConverter.ConvertiblePair |
转换方法 | convert(Object source,TypeDescriptor sourceType,TypeDescriptor targetType) |
类型描述 | org.springframework.core.convert.TypeDescriptor |
优化GenericConverter 接口
GenericConverter 局限性
缺少Source Type
和Target Type
前置判断
单一类型转换实现复杂GenericConverter 优化接口 -
ConditionalGenericConverter
复合类型转换:org.springframework.core.convert.converter.GenericConverter
类型条件判断:org.springframework.core.convert.converter.ConditionalConverter
扩展Spring 类型转换器
实现转换器接口
org.springframework.core.convert.converter.Converter
org.springframework.core.convert.converter.ConverterFactory
org.springframework.core.convert.converter.GenericConverter
注册转换器实现
通过ConversionServiceFactoryBean Spring Bean
通过org.springframework.core.convert.ConversionService API
统一类型转换服务
- org.springframework.core.convert.ConversionService
实现类型 | 说明 |
---|---|
GenericConversionService | 通用ConversionService模板实现,不内置转化器实现 |
DefaultConversionService | 基础ConversionSerivce实现,内置常用转化器实现 |
FormattingConversionService | 通用Formatter + GenericConversionService 实现,不内置转化器和Formatter实现 |
DefaultFormattingConversionService | DefaultConversionService + 格式化实现(如:JSR-354 Money & Currency,JSR-310 Date-Time) |
ConversionService 作为依赖
-
类型转换器底层接口 - org.springframework.beans.TypeConverter
- 起始版本:Spring 2.0
- 核心方法 -
convertIfNecessary
重载方法- 抽象实现 -
org.springframework.beans.TypeConverterSupport
- 简单实现 -
org.springframework.beans.SimpleTypeConverter
-
类型转换器底层抽象实现
- 实现接口 -
org.springframework.beans.TypeConverter
- 扩展实现 -
org.springframework.beans.PropertyEditorRegistrySupport
- 委派实现 -
org.springframework.beans.TypeConverterDelegate
-
类型转换器底层委派实现 - org.springframework.beans.TypeConverterDelegate
- 构造来源 -
org.springframework.beans.AbstractNestablePropertyAccessor
实现
org.springframework.beans.BeanWrapperImpl
- 依赖 - java.beans.PropertyEditor 实现
默认内建实现 -
PropertyEditorRegistrySupport#registerDefaultEditors
- 可选依赖 -
org.springframework.core.convert.ConversionService
实现
Spring 类型转换实现有哪些?
- 基于JavaBeans PropertyEditor 接口实现
- Spring 3.0+ 通用类型转换实现
Spring 类型转换器接口有哪些?
类型转换接口 -
org.springframework.core.convert.converter.Converter
通用类型转换接口 -
org.springframework.core.convert.converter.GenericConverter
类型条件接口 -
org.springframework.core.convert.converter.ConditionalConverter
综合类型转换接口 -
org.springframwork.core.convert.converter.ConditionalGenericConverter
Java 泛型基础
- 泛型类型
泛型类型是在类型上参数化的泛型类或接口
- 泛型使用场景
- 编译时强类型检查
- 避免类型强转
- 实现通用算法
- 泛型类型擦写
泛型被引入到 Java 语言中,以便在编译时提供更严格的类型检查并支持泛型编程。类型擦除确保不会为参数化类型创建新类;因此,泛型不会产生运行时开销。为了实现泛型,编译器将类型擦除应用于:
- 将泛型类型中的所有类型参数替换为其边界,如果类型参数是无边界的,则将其替换为“Object”。因此,生成的字节码只包含普通类、接口和方法
- 必要时插入类型转换以保持类型安全
- 生成桥方法以保留扩展泛型类型中的多态性
Java 5 类型接口
- Java 5 类型接口 - java.lang.reflect.Type
派生类或接口 | 说明 |
---|---|
java.lang.Class | Java 类 API,如java.lang.String |
java.lang.reflect.GenericArrayType | 泛型数组类型 |
java.lang.reflect.ParameterizedType | 泛型参数类型 |
java.lang.reflect.TypeVariable | 泛型类型变量,如Collection<E>中的E |
java.lang.reflect.WildcardType | 泛型通配类型 |
- Java 泛型反射 API
类型 | API |
---|---|
泛型信息(Generics Info) | java.lang.Class#getGenericInfo() |
泛型参数(Parameters) | java.lang.reflect.ParameterizedType |
泛型父类(Super Classes) | java.lang.Class#getGenericSuperclass() |
泛型接口(Interfaces) | java.lang.Class#getGenericInterfaces() |
泛型声明(Generics Delaration) | java.lang.reflect.GenericDeclaration |
Spring 泛型类型辅助类
- 核心 API - org.springframework.core.GenericTypeResolver
• 版本支持:[2.5.2 , )
• 处理类型相关(Type)相关方法
• resolveReturnType
• resolveType
• 处理泛型参数类型(ParameterizedType)相关方法
• resolveReturnTypeArgument
• resolveTypeArgument
• resolveTypeArguments
• 处理泛型类型变量(TypeVariable)相关方法
• getTypeVariableMap
Spring 泛型集合类型辅助类
- 核心 API - org.springframework.core.GenericCollectionTypeResolver
- 版本支持:[2.0 , 4.3]
- 替换实现:org.springframework.core.ResolvableType
- 处理 Collection 相关
• getCollection*Type
- 处理 Map 相关
• getMapKey*Type
• getMapValue*Type
Spring 方法参数封装
- 核心 API - org.springframework.core.MethodParameter
- 起始版本:[2.0 , )
- 元信息
• 关联的方法 - Method
• 关联的构造器 - Constructor
• 构造器或方法参数索引 - parameterIndex
• 构造器或方法参数类型 - parameterType
• 构造器或方法参数泛型类型 - genericParameterType
• 构造器或方法参数参数名称 - parameterName
• 所在的类 - containingClass
Spring 4.0 泛型优化实现 - ResolvableType
- 核心 API - org.springframework.core.ResolvableType
• 起始版本:[4.0 , )
• 扮演角色:GenericTypeResolver 和 GenericCollectionTypeResolver 替代者
• 工厂方法:for* 方法
• 转换方法:as* 方法
• 处理方法:resolve* 方法
ResolvableType 的局限性
• 局限一:ResolvableType 无法处理泛型擦写
• 局限二:ResolvableType 无法处理非具体化的 ParameterizedType
Java 泛型擦写发生在编译时还是运行时?
运行时
请介绍 Java 5 Type 类型的派生类或接口?
- java.lang.Class
- java.lang.reflect.GenericArrayType
- java.lang.reflect.ParameterizedType
- java.lang.reflect.TypeVariable
- java.lang.reflect.WildcardType
请说明 ResolvableType 的设计优势?
- 简化 Java 5 Type API 开发,屏蔽复杂 API 的运用,如 ParameterizedType
- 不变性设计(Immutability)
- Fluent API 设计(Builder 模式),链式(流式)编程
Java事件/监听器编程模型
- 设计模式 - 观察者模式扩展
- 可观者对象(消息发送者)- java.util.Observable
- 观察者 - java.util.Observer
- 标准化接口
- 事件对象 - java.util.EventObject
- 事件监听器 - java.util.EventListener
面向接口的事件/监听器设计模式
- 事件/监听器场景举例
Java技术规范 | 事件接口 | 监听器接口 |
---|---|---|
JavaBeans | java.beans.PropertyChangeEvent | java.beans.PropertyChangeListener |
Java AWT | java.awt.event.MouseEvent | java.awt.event.MouseListener |
Java Swing | javax.swing.event.MenuEvent | javax.swing.event.MenuListener |
Java Preference | java.util.prefs.PreferenceChangeEvent | java.util.prefs.PreferenceChangeListener |
面向注解的事件/监听器设计模式
- 事件/监听器注解场景举例
Java技术规范 | 事件注解 | 监听器注解 |
---|---|---|
Servlet 3.0+ | @javax.servlet.annotation.WebListener | |
JPA 1.0+ | @javax.persistence.PostPersist | |
Java Common | @PostConstruct | |
EJB 3.0+ | @javax.ejb.PrePassivate | |
JSF 2.0+ | @javax.faces.event.ListenerFor |
Spring 标准事件 - ApplicationEvent
- Java 标准事件 java.util.EventObject 扩展
扩展特性:事件发生事件戳
- Spring 应用上下文 ApplicationEvent扩展 - ApplicationContextEvent
- Spring 应用上下文(ApplicationContext)作为事件源
- 具体实现
- org.springframework.context.event.ContextClosedEvent
- org.springframework.context.event.ContextRefreshedEvent
- org.springframework.context.event.ContextStartedEvent
- org.springframework.context.event.ContextStoppedEvent
基于接口的Spring事件监听器
- Java 标准事件监听器 java.util.EventListener 扩展
- 扩展接口 - org.springframework.context.ApplicationListener
- 设计特点: 单一类型事件处理
- 处理方法:onApplicationEvent(ApplicationEvent)
- 事件类型:org.springframework.context.ApplicationEvent
基于注解的 Spring 事件监听器
- Spring 注解 - @org.springframework.context.event.EventListener
特性 | 说明 |
---|---|
设计特点 | 支持多ApplicationEvent类型,无需接口约束 |
注解目标 | 方法 |
是否支持异步执行 | 支持 |
是否支持泛型类型事件 | 支持 |
是否支持顺序控制 | 支持,配合@order 注解控制 |
注册Spring ApplicationListener
方法一:ApplicationListener 作为Spring Bean 注册
方法二:通过ConfigurableApplicationContext API注册
Spring 事件发布器
方法一:通过 ApplicationEventPublisher 发布 Spring 事件
- 获取ApplicationEventPublisher
- 依赖注入
方法二:通过ApplicationEventMulticaster 发布 Spring 事件
- 获取ApplicationEventMulticaster
- 依赖注入
- 依赖查找
Spring 层次性上下文事件传播
- 发生说明
当Spring 应用出现多层次Spring 应用上下文(ApplicationContext)时,如Spring WebMVC、Spring Boot 或Spring Cloud场景下,由子ApplicationContext 发起Spring事件可能会传递到其Parent ApplicationContext(直到Root)的过程
- 如何避免
定位Spring事件源(ApplicationContext)进行过滤处理
Spring 内建事件
- ApplicationContextEvent 派生事件
- ContextRefreshedEvent:Spring 应用上下文就绪事件
- ContextStartedEvent:Spring 应用上下文启动事件
- ContextStoppedEvent:Spring 应用上下文停止事件
- ContextClosedEvent:Spring 应用上下文关闭事件
Spring 4.2 Payload 事件
- Spring Payload 事件 - org.springframework.context.PayloadApplicationEvent
- 使用场景:简化 Spring 事件发送,关注事件源主体
- 发送方法
ApplicationEventPublisher#publishEvent(java.lang.Object)
自定义 Spring 事件
- 扩展 org.springframework.context.ApplicationEvent
- 实现 org.springframework.context.ApplicationListener
- 注册 org.springframework.context.ApplicationListener
依赖注入ApplicationEventPublisher
- 通过ApplicationEventPublisherAware 回调接口
- 通过@Autowired ApplicationEventPublisher
依赖查找ApplicationEventMulticaster
- 查找条件
- Bean 名称:“applicationEventMulticaster”
- Bean 类型:org.springframework.context.event.ApplicationEventMulticaster
ApplicationEventPublisher 底层实现
- 底层实现
- 接口:org.springframework.context.event.ApplicationEventMulticaster
- 抽象类:org.springframework.context.event.AbstractApplicationEventMulticaster
- 实现类:org.springframework.context.event.SimpleApplicationEventMulticaster
同步和异步Spring 事件广播
- 基于实现类 - org.springframework.context.event.SimpleApplicationEventMulticaster
- 模式切换:setTaskExecutor(java.util.concurrent.Executor) 方法
默认模式:同步
异步模式:如 java.util.concurrent.ThreadPoolExecutor
- 设计缺陷:非基于接口契约编程
- 基于注解 - @org.springframework.context.event.EventListener
- 模式切换
默认模式:同步
异步模式:标注 @org.springframework.scheduling.annotation.Async
- 实现限制:无法直接实现同步/异步动态切换
Spring4.1 事件异常处理
- Spring 3.0 错误处理接口 - org.springframework.util.ErrorHandler
使用场景
- Spring 事件(Events)
SimpleApplicationEventMulticaster Spring 4.1 开始支持
- Spring 本地调度(Scheduling)
org.springframework.scheduling.concurrent.ConcurrentTaskScheduler
org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler
Spring 事件/监听器实现原理
- 核心类 - org.springframework.context.SimpleApplicationEventMulticaster
- 设计模式:观察者模式扩展
被观察者 - org.springframework.context.ApplicationListener
API 添加
依赖查找
通知对象 - org.springframework.context.ApplicationEvent
- 执行模式:同步/异步
- 异常处理:org.springframework.core.ErrorHandler
- 泛型处理:org.springframework.core.ResolvableType
Spring Boot 事件
事件类型 | 发生时机 |
---|---|
ApplicationStartingEvent | 当Spring Boot 应用已启动时 |
ApplicationStartedEvent | 当Spring Boot 应用启动了 |
ApplicationEnvironmentPreparedEvent | 当Spring Boot Environment 实例已准备时 |
ApplicationPreparedEvent | 当Spring Boot 应用预备时 |
ApplicationReadyEvent | 当Spring Boot 应用完全可用时 |
ApplicationFailedEvent | 当Spring Boot 应用启动失败时 |
Spring Cloud 事件
事件类型 | 发生时机 |
---|---|
EnvironmentChangeEvent | 当 Environment 实例配置属性发生变化时 |
HeartbeatEvent | 当 DiscoveryClient 客户端发送心跳时 |
InstancePreRegisteredEvent | 当服务实例注册前 |
InstanceRegisteredEvent | 当服务实例注册后 |
RefreshEvent | 当 RefreshEndpoint 被调用时 |
RefreshScopeRefreshedEvent | 当Refresh Scope Bean 刷新后 |
Spring 事件核心接口/组件?
- Spring 事件 - org.springframework.context.ApplicationEvent
- Spring 事件监听器 - org.springframework.context.ApplicationListener
- Spring 事件发布器 - org.springframework.context.ApplicationEventPublisher
- Spring 事件广播器 - org.springframework.context.event.ApplicationEventMulticaster
Spring 同步和异步事件处理的使用场景?
- Spring 同步事件
绝大多数Spring使用场景,如ContextRefreshedEvent
- Spring 异步事件
主要@EventListener 与 @Asyc配合,实现异步处理,不阻塞主线程,比如长时间的数据计算任务等,不要轻易调整SimpleApplicationEventMulticaster中关联的taskExecutor 对象,除非使用者非常了解Spring 事件机制,否则容易出现异常行为
Spring 注解驱动编程发展历程
注解驱动启蒙时代:Spring Framework 1.x
注解驱动过渡时代:Spring Framework 2.x
注解驱动黄金时代:Spring Framework 3.x
注解驱动完善时代:Spring Framework 4.x
注解驱动当下时代:Spring Framework 5.x
Spring 核心注解场景分类
- Spring 模式注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Repository | 数据仓储模式注解 | 2.0 |
@Component | 通用组件模式注解 | 2.5 |
@Service | 服务模式注解 | 2.5 |
@Controller | Web 控制器模式注解 | 2.5 |
@Configuration | 配置类模式注解 | 3.0 |
- 装配注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@ImportResource | 替换XML元素<import> | 2.5 |
@Import | 导入Configuration 类 | 2.5 |
@ComponentScan | 扫描指定package 下标注Spring模式注解的类 | 3.1 |
- 依赖注入注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Autowired | Bean 依赖注入,支持多种依赖查找方式 | 2.5 |
@Qualifier | 细粒度的@Autowired 依赖查找 | 2.5 |
Spring 注解编程模型(https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model)
- 元注解(Meta-Annotations)
- Spring 模式注解(Stereotype Annotations)
- Spring 组合注解(Composed Annotations)
- Spring 注解属性别名和覆盖(Attribute Aliases and Overrides)
Spring 元注解(Meta-Annotations)
- 官方Wiki 原文
A meta-annotation is an annotation that is declared on another annotation. An annotation is therefore meta-annotated if it is annotated with another annotation. For example, any annotation that is declared to be documented is meta-annotated with
@Documented
from thejava.lang.annotation
package.
- 举例说明
java.lang.annotation.Documented
java.lang.annotation.Inherited
java.lang.annotation.Repeatable
Spring 模式注解(Stereotype Annotations)
- 官方Wiki原文
A stereotype annotation is an annotation that is used to declare the role that a component plays within the application. For example, the
@Repository
annotation in the Spring Framework is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO).
@Component
is a generic stereotype for any Spring-managed component. Any component annotated with@Component
is a candidate for component scanning. Similarly, any component annotated with an annotation that is itself meta-annotated with@Component
is also a candidate for component scanning. For example,@Service
is meta-annotated with@Component
.Core Spring provides several stereotype annotations out of the box, including but not limited to:
@Component
,@Service
,@Repository
,@Controller
,@RestController
, and@Configuration
.@Repository
,@Service
, etc. are specializations of@Component
.
- 理解@Component “派生性”
元标注@Component 的注解在XML 元素<context:component-scan>或注解@ComponentScan 扫描中“派生”了@Component 的特性,并且从Spring Framework4.0 开始支持多层次“派生性”
- 举例说明
- @Repository
- @Service
- @Controller
- @Configuration
- @SpringBootConfiguration(Spring Boot)
- @Component “派生性”原理
- 核心组件 - org.springframework.context.annotation.ClassPathBeanDefinitionScanner
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
- 资源处理 - org.springframework.core.io.support.ResourcePatternResolver
- 资源 - 类元信息
org.springframework.core.type.classreading.MetadataReaderFactory
- 类元信息 - org.springframework.core.type.ClassMetadata
ASM 实现 - org.springframework.core.type.classreading.ClassMetadataReadingVisitor
反射实现 - org.springframework.core.type.StandardAnnotationMetadata
- 注解元信息 - org.springframework.core.type.AnnotationMetadata
ASM 实现 - org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor
反射实现 - org.springframework.core.type.StandardAnnotationMetadata
Spring 组合注解(Composed Annotations)
- 官方Wiki 原文
A composed annotation is an annotation that is meta-annotated with one or more annotations with the intent of combining the behavior associated with those meta-annotations into a single custom annotation. For example, an annotation named
@TransactionalService
that is meta-annotated with Spring's@Transactional
and@Service
annotations is a composed annotation that combines the semantics of@Transactional
and@Service
.@TransactionalService
is technically also a custom stereotype annotation.
- 基本定义
Spring 组合注解(Composed Annotations)中的元注允许是Spring模式注解(Stereotype Annotation)与其他Spring 功能性注解的任意组合
Spring 注解属性别名(Attribute Aliases)
- 官方Wiki 原文
An attribute alias is an alias from one annotation attribute to another annotation attribute. Attributes within a set of aliases can be used interchangeably and are treated as equivalent. Attribute aliases can be categorized as follows.
- Explicit Aliases: if two attributes in one annotation are declared as aliases for each other via
@AliasFor
, they are explicit aliases.- Implicit Aliases: if two or more attributes in one annotation are declared as explicit overrides for the same attribute in a meta-annotation via
@AliasFor
, they are implicit aliases.- Transitive Implicit Aliases: given two or more attributes in one annotation that are declared as explicit overrides for attributes in meta-annotations via
@AliasFor
, if the attributes effectively override the same attribute in a meta-annotation following the law of transitivity, they are transitive implicit aliases.
Spring 注解属性覆盖(Attribute Overrides)
- 官方Wiki 原文
An attribute override is an annotation attribute that overrides (or shadows) an annotation attribute in a meta-annotation. Attribute overrides can be categorized as follows.
- Implicit Overrides: given attribute
A
in annotation@One
and attributeA
in annotation@Two
, if@One
is meta-annotated with@Two
, then attributeA
in annotation@One
is an implicit override for attributeA
in annotation@Two
based solely on a naming convention (i.e., both attributes are namedA
).- Explicit Overrides: if attribute
A
is declared as an alias for attributeB
in a meta-annotation via@AliasFor
, thenA
is an explicit override forB
.- Transitive Explicit Overrides: if attribute
A
in annotation@One
is an explicit override for attributeB
in annotation@Two
andB
is an explicit override for attributeC
in annotation@Three
, thenA
is a transitive explicit override forC
following the law of transitivity.
Spring @Enable 模块驱动
- @Enable 模块驱动
@Enable 模块驱动是以@Enable 为前缀的注解驱动编程模型,所谓“模块”是指具备相同领域的功能组件集合,组合所形成一个独立的单元。比如Web MVC模块、AspectJ代理模块、Caching(缓存)模块、JMX(Java管理扩展)模块、Async(异步处理)模块等
- 举例说明
- @EnableWebMvc
- @EnableTransactionManagement
- @EnableCaching
- @EnableMBeanExport
- @EnableAsync
- @Enable 模块驱动编程模式
- 驱动注解:@EnableXXX
- 导入注解:@Import 具体实现
- 具体实现
- 基于Configuration Class
- 基于ImportSelector 接口实现
- 基于ImportBeanDefinitionRegistrar 接口实现
Spring 条件注解
- 基于配置条件注解 - @org.springframework.context.annotation.Profile
关联对象 - org.springframework.core.env.Environment 中的 Profiles
实现变化:从Spring 4.0 开始,@Profile 基于@Conditional 实现
- 基于编程条件注解 - org.springframework.context.annotation.Conditional
关联对象 - org.springframework.context.annotation.Condition 具体实现
- @Conditional 实现原理
- 上下文对象 - org.springframework.context.annotation.ConditionContext
- 条件判断 - org.springframework.context.annotation.ConditionEvaluator
- 配置阶段 - org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase
- 判断入口 - org.springframework.context.annotation.ConfigurationClassPostProcessor
org.springframework.context.annotation.ConfigurationClassParser
Spring Boot 注解
注解 | 场景说明 | 起始版本 |
---|---|---|
@SpringBootConfiguration | Spring Boot 配置类 | 1.4.0 |
@SpringBootApplication | Spring Boot 应用引导注解 | 1.2.0 |
@EnableAutoConfiguration | Spring Boot 激活自动转配 | 1.0.0 |
Spring Cloud 注解
注解 | 场景说明 | 起始版本 |
---|---|---|
@SpringCloudApplication | Spring Cloud 应用引导注解 | 1.0.0 |
@EnableDiscoveryClient | Spring Cloud 激活服务发现客户端注解 | 1.0.0 |
@EnableCircuitBreaker | Spring Cloud 激活熔断注解 | 1.0.0 |
Spring 模式注解有哪些?
- @org.springframework.stereotype.Component
- @org.springframework.stereotype.Repository
- @org.springframework.stereotype.Service
- @org.springframework.stereotype.Controller
- @org.springframework.context.annotation.Configuration
@EventListener的工作原理?
详见源码:org.springframework.context.event.EventListenerMethodProcessor
理解 Spring Environment 抽象
- 统一的Spring 配置属性管理
Spring Framework 3.1 开始引入 Environment 抽象,它统一Spring 配置属性的存储,包括占位符处理和类型转换,不仅完整地替换PropertyPlaceholderConfigurer,而且还支持更丰富的配置属性源(PropertySource)
- 条件化 Spring Bean 装配管理
通过Environment Profiles 信息,帮助Spring 容器提供条件化地装配Bean
Spring Environment 接口使用场景
- 用于属性占位符处理
- 用于转换Spring配置属性类型
- 用于存储Spring 配置属性源
- 用于Profiles 状态的维护
Environment 占位符处理
- Spring 3.1 前占位符处理
组件:org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
接口:org.springframework.util.StringValueResolver
- Spring 3.1+ 占位符处理
组件:org.springframework.context.support.PropertySourcesPlaceholderConfigurer
接口:org.springframework.beans.factory.config.EmbeddedValueResolver
理解条件配置Spring Profiles
- Spring 3.1 条件配置
- API:org.springframework.core.env.ConfigurableEnvironment
修改:addActiveProfile(String)、setActiveProfiles(String...)和setDefaultProfiles(String...)
获取:getActiveProfiles() 和 getDefaultProfiles()
匹配:acceptsProfiles(String...) 和 acceptsProfiles(Profiles)
- 注解:@org.springframework.context.annotation.Profile
- 基于Spring 4 org.springframework.context.annotation.Condition 接口实现
org.springframework.context.annotation.ProfileCondition
依赖注入 Environment
- 直接依赖注入
通过EnvironmentAware 接口回调
通过@Autowired 注入 Environment
- 间接依赖注入
通过 ApplicationContextAware 接口回调
通过@Autowired 注入ApplicationContext
依赖查找Environment
- 直接依赖查找
通过org.springframework.context.ConfigurableApplicationContext#ENVIRONMENT_BEAN_NAME
- 间接依赖查找
通过 org.springframework.context.ConfigurableApplicationContext#getEnvironment
依赖注入@Value
- 通过注入@Value
实现 - org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
Spring 类型转换在 Environment 中的运用
- Environment 底层实现
- 底层实现 - org.springframework.core.env.PropertySourcesPropertyResolver
核心方法 - convertValueIfNecessary(Object,Class)
- 底层服务 - org.springframework.core.convert.ConversionService
默认实现 - org.springframework.core.convert.support.DefaultConversionService
Spring 类型转换在@Value 中的运用
- @Value 底层实现
- 底层实现 - org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
- 底层服务 - org.springframework.beans.TypeConverter
默认实现 - org.springframework.beans.TypeConverterDelegate
java.beans.PropertyEditor
org.springframework.core.convert.ConversionService
Spring 配置属性源 PropertySource
- API
单配置属性源 - org.springframework.core.env.PropertySource
多配置属性源 - org.springframework.core.env.PropertySources
- 注解
单配置属性源 - @org.springframework.context.annotation.PropertySource
多配置属性源 - @org.springframework.context.annotation.PropertySources
- 关联
存储对象 - org.springframework.core.env.MutablePropertySources
关联方法 - org.springframework.core.env.ConfigurableEnvironment#getPropertySources()
Spring 内建的配置属性源
- 内建 PropertySource
PropertySource 类型 | 说明 |
---|---|
org.springframework.core.env.CommandLinePropertySource | 命令行配置属性源 |
org.springframework.jndi.JndiPropertySource | JNDI 配置属性源 |
org.springframework.core.env.PropertiesPropertySource | Properties 配置属性源 |
org.springframework.web.context.support.ServletConfigPropertySource | Serlvet 配置属性源 |
org.springframework.web.context.support.ServletContextPropertySource | ServletContext 配置属性源 |
org.springframework.core.env.SystemEnvironmentPropertySource | 环境变量配置属性源 |
... | ... |
基于注解扩展 Spring 配置属性源
- @org.springframework.context.annoatation.PropertySource 实现原理
- 入口 - org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass
org.springframework.context.annotation.ConfigurationClassParser#processPropertySource
- 4.3 新增语义
配置属性字符编码 - encoding
org.springframework.core.io.support.PropertySourceFactory
- 适配对象 - org.springframework.core.env.CompositePropertySource
基于API 扩展Spring 配置属性源
Spring 应用上下文启动前装配 PropertySource
Spring 应用上下文启动后装配 PropertySource
简单介绍 Spring Environment 接口?
- 核心接口 - org.springframework.core.env.Environment
- 父接口 - org.springframework.core.env.PropertyResolver
- 可配置接口 - org.springframework.core.env.ConfigurableEnvironment
- 职责
管理Spring 配置属性源
管理Profiles
Spring 应用上下文启动准备阶段
- 启动时间 - startupDate
- 状态标识 - closed(false)、active(true)
- 初始化 PropertySources - initPropertySources()
- 检验Environment 中必须属性
- 初始化事件监听器集合
- 初始化早期Spring 事件集合
BeanFactory 创建阶段
- AbstractApplicationContext#obtainFreshBeanFactory()方法
- 刷新Spring 应用上下文底层BeanFactory - refreshBeanFactory()
- 销毁或关闭BeanFactory,如果已存在的话
- 创建BeanFactory - createBeanFactory()
- 设置BeanFactory Id
- 设置“是否允许BeanDefinition重复定义” - customizeBeanFactory(DefaultListableBeanFactory)
- 设置“是否运行循环引用(依赖)” - customizeBeanFactory(DefaultListableBeanFactory)
- 加载BeanDefinition - loadBeanDefinitions(DefaultListableBeanFactory)方法
- 关联新建 BeanFactory 到 Spring 应用上下文
- 返回Spring 应用上下文底层BeanFactory - getBeanFactory()
BeanFactory准备阶段
- AbstractApplicationContext#prepareBeanFactory(ConfigurableListableBeanFactory)
关联 ClassLoader
设置Bean表达式处理器
添加 PropertyEditorRegistrar 实现 - ResourceEditorRegistrar
添加 Aware 回调接口 BeanPostProcessor 实现 - ApplicationContextAwareProcessor
忽略 Aware 回调接口作为依赖注入接口
注册 ResolvableDependency 对象 - BeanFactory、ResourceLoader、ApplicationEventPublisher 以及 ApplicationContext
注册 ApplicationListenerDetector 对象
注册 LoadTimeWeaverAwareProcessor 对象
注册单例对象 - Environment、Java System Properties 以及 OS 环境变量
BeanFactory 后置处理阶段
- AbstractApplicationContext#postProcessBeanFactory(ConfigurableListableBeanFactory) 方法
由子类覆盖该方法
- AbstractApplicationContext#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory)方法
调用 BeanFactoryPostProcessor 或 BeanDefinitionRegistry 后置处理方法
注册 LoadTimeWeaverAwareProcessor 对象
BeanFactory 注册 BeanPostProcessor 阶段
- AbstractApplicationContext#registerBeanPostProcessors(ConfigurableListableBeanFactory) 方法
注册 PriorityOrdered 类型的 BeanPostProcessor Beans
注册 Ordered 类型的BeanPostProcessor Beans
注册普通 BeanPostProcessor Beans
注册 MergedBeanDefinitionPostProcessor Beans
注册 ApplicationListenerDetector 对象
初始化内建Bean:MessageSource
AbstractApplicationContext#initMessageSource() 方法
初始化内建Bean:Spring 事件广播器
AbstractApplicationContext#initApplicationEventMulticaster() 方法
Spring 应用上下文刷新阶段
- AbstractApplicationContext#onRefresh() 方法
子类覆盖该方法
- org.springframework.web.context.support.AbstractRefreshableWebApplicationContext#onRefresh()
- org.springframework.web.context.support.GenericWebApplicationContext#onRefresh()
- org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext#onRefresh()
- org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh()
- org.springframework.web.context.support.StaticWebApplicationContext#onRefresh()
Spring 事件监听器注册阶段
- AbstractApplicationContext#registerListeners() 方法
- 添加当前应用上下文所关联的ApplicationListener 对象(集合)
- 添加BeanFactory 所注册 ApplicationListener Beans
- 广播早期 Spring 事件
BeanFactory 初始化完成阶段
- AbstractApplicationContext#finishBeanFactoryInitialization(ConfigurableListableBeanFactory) 方法
- BeanFactory 关联 ConversionService Bean,如果存在
- 添加 StringValueResolver 对象
- 依赖查找 LoadTimeWeaverAware Bean
- BeanFactory 临时 ClassLoader 置为 null
- BeanFactory 冻结配置
- BeanFactory 初始化非延迟单例Beans
Spring 应用上下文刷新完成阶段
- AbstractApplicationContext#finishRefresh() 方法
- 清除 ResourceLoader 缓存 - clearResourceCaches() @since 5.0
- 初始化 LifecycleProcessor 对象 - initLifecycleProcessor()
- 调用LifecycleProcessor#onRefresh() 方法
- 发布Spring 应用上下文已刷新事件 - ContextRefreshedEvent
- 向MBeanServer 托管 Live Beans
Spring 应用上下文启动阶段
- AbstractApplicationContext#start()方法
- 启动 LifecycleProcessor
依赖查找Lifecycle Bean
启动Lifecycle Beans
- 发布Spring 应用上下文已启动事件 - ContextStartedEvent
Spring 应用上下文停止阶段
- AbstractApplicationContext#stop()方法
- 停止LifecycleProcessor
依赖查找 Lifecycle Bean
停止 Lifecycle Beans
- 发布Spring 应用上下文已停止事件 - ContextStoppedEvent
Spring 应用上下文关闭阶段
- AbstractApplicationContext#close() 方法
- 状态标识:active(false)、closed(true)
- Live Beans JMX 撤销托管
LiveBeansView.unregisterApplicationContext(ConfigurableApplicationContext)
- 发布Spring 应用上下文已关闭事件 - ContextClosedEvent
- 关闭 LifecycleProcessor
依赖查找 Lifecycle Beans
停止 Lifecycle Beans
- 销毁 Spring Beans
- 关闭 BeanFactory
- 回调 onClose()
- 注册 Shutdown Hook 线程(如果有注册)
Spring 应用上下文生命周期有哪些阶段?
- 刷新阶段 - ConfigurableApplicationContext#refresh()
- 启动阶段 - ConfigurableApplicationContext#start()
- 停止阶段 - ConfigurableApplicationContext#stop()
- 关闭阶段 - ConfigurableApplicationContext#close()