Compare commits

...

5 Commits

Author SHA1 Message Date
kn5886348135 b59e7b4c4b 排序算法和二叉树
3 years ago
kn5886348135 7e2d22e6af 单例和工厂方法模式
3 years ago
kn5886348135 218315670e 设计模式概述
3 years ago
kn5886348135 a5fdbb8a02 Spring生命周期概述
3 years ago
kn5886348135 35aa4eb264 添加ConfigurationClassPostProcessor
3 years ago

@ -32,3 +32,21 @@ private static void printCompleteBinaryStr(int num){
Integer.MIN_VALUE取反加一后仍然为Integer.MIN_VALUE这不是bug。
Integer.MAX_VALUE加1后溢出为Integer.MIN_VALUEInteger.MIN_VALUE减一则溢出为Integer.MAX_VALUE。
异或运算满足交换律和结合律
a^b=b^a
(a^b)^c=a^(b^c)
a、b交换
a=a^b
b=a^b
a=a^b
给定数组arr只有一个数出现了奇数次其它数都是偶数次找到并打印这个数。
偶数次异或为0奇数次异或为本身遍历每一个元素并异或最后结果就是奇数次的数字。
拿到一个数二进制最右侧的1
a&(~a+1)
给定数组arr只有一种数出现了K次其他数都出现M次。
假设a出现k次b出现m次
将所有数字的二进制位相加则t[i] % m就是a的二进制在i位置次数要么是0要么是k

@ -92,3 +92,41 @@ private static void insertSort(int[] arr){
}
}
```
不基于比较的排序也叫桶排序。对数据样本有要求但是特定场景可以做到O(N)时间复杂度基于比较的排序最好能做到O(N*logN)
计数排序 需要指定上下限
基数排序 非负、能用十进制理解的样本
排序的稳定性
稳定排序 冒泡、插入、归并
不稳定排序 选择、快排、堆排序、希尔
|序号|名称 |时间复杂度 |额外空间复杂度|稳定性|
|:----- |:----- |:-----|:-----|:-----|:-----| :-----| ----: | :----: |
|1|选择排序 |O(N^2^) |O(1) |无|
|2|冒泡排序 |O(N^2^) |O(1) |有|
|3|插入排序 |O(N^2^) |O(1) |有|
|4|归并排序 |O(N$\times$ $\log$N) |O(N) |有|
|5|随机快排 |O(N$\times$ $\log$N) |O($\log$N) |无|
|6|堆排序 |O(N$\times$ $\log$N) |O(1) |无|
|7|计数排序 |O(N) |O(M) |有|
|8|基数排序 |O(N) |O(N) |有|
|9|希尔排序 | | ||
* 不基于比较的排序,对样本数据有严格要求,不容易改写
* 基于比较的排序,只要规定好两个样本怎么比较大小就可以直接复用
* 基于比较的排序时间复杂度的极限是O(N$\times$ $\log$N)
* 时间复杂度O(N$\times$ $\log$N)、额外空间复杂度低于O(N)、且稳定的基于比较的排序是不存在的
* 为了绝对的速度选择快排、为了省空间选堆排序、为了稳定性选归并
工程上的改进
* 考虑稳定性Arrays.sort基础类型使用快排有比较器使用归并排序。
* 充分利用O(N$\times$ $\log$N)和O(N^2^)排序各自的优势O(N^2^)排序的常数项小,在数据样本不大(比如小于60)的时候是比O(N$\times$ $\log$N)要快的。
单链表回文
L1、L2、L3、L4、L5、L6、L7、R1、R2、R3、R4、R5、R6、R7变成L1、R7、L2、R6、L3、R5、L4、R4、L5、R3、L6、R2、L7、R1
单链表找中间节点
单链表荷兰国旗问题
给定表头将节点数据按照小于、等于、大于K连接

@ -116,3 +116,7 @@ private static boolean validateArr(int[] arr) {
return true;
}
```
小和问题、逆序对、大于两倍问题
区间和leetcode327 可以用有序表、归并解决
荷兰国旗问题

@ -18,7 +18,7 @@ private static int binarySearch(int[] arr, int target) {
int index = -1;
int middle;
while (left <= right) {
middle = (left + right) >> 1;
middle = left + ((right-left) >> 1);
if (arr[middle] == target) {
index = middle;
return index;
@ -42,7 +42,7 @@ private static int binarySearchLeft(int[] arr, int target) {
int index = -1;
int middle;
while (left <= right) {
middle = (left + right) >> 1;
middle = left + ((right-left) >> 1);
if (arr[middle] >= target) {
index = middle;
right = middle - 1;
@ -64,7 +64,7 @@ private static int binarySearchRight(int[] arr, int target) {
int index = -1;
int middle;
while (left <= right) {
middle = (left + right) >> 1;
middle = left + ((right-left) >> 1);
if (arr[middle] <= target) {
index = middle;
left = middle + 1;
@ -99,7 +99,8 @@ public int localMin(int[] arr){
int index = -1;
int middle;
while (left <= right) {
middle = (left + right) >> 1;
// 避免溢出
middle = left + ((right-left) >> 1);
if (arr[middle - 1] < arr[middle]) {
right = middle - 1;
} else if (arr[middle + 1] < arr[middle]) {

@ -35,7 +35,11 @@ private static Node reverDoubleLinkedList(Node head) {
}
```
把给定值都删除
单链表实现队列和栈
双链表实现队列和栈
数组实现队列和栈
### 使用双链表实现双端队列
@ -85,3 +89,16 @@ public class BitMap {
减法delete add(a,add(~b,1))取反加1后为负数。
乘法 a左移b的每一位进制的位数相加。
除法 先取绝对值a右移到刚好大于等于b拿到一个商最后所有商相加补上符号。对系统最小值特殊处理。
只用栈结构实现队列结构
只用队列结构实现栈结构
图的宽度优先搜索,使用队列实现,图的深度优先搜索,实现栈实现
栈和队列互换后可以实现
图的宽度优先搜索,使用栈实现,图的深度优先搜索,实现队列实现
不考虑时间复杂度
任何地柜都可以改成非递归方式实现。将系统压栈改为自定义实现,则可以避免递归。
master公式预估递归的时间复杂度要求子问题数据规模一样。
小和问题

@ -21,18 +21,28 @@
先序遍历的第一个元素是头结点先序遍历剩余部分左边是左节点的先序右边是右节点的先序中序遍历左边是左节点的中序右边是右节点的中序。递归构建二叉树递归函数入参为先序遍历的起止index中序遍历的起止index返回头结点。
### 二叉树按层遍历收集节点 LeetCode107 LeetCode102
#### 二叉树按层遍历收集节点 LeetCode107 LeetCode102
使用LinkedList(有序,快速插入),递归将每一层的节点入队、出队。
### 平衡二叉树 LeetCode110
#### 平衡二叉树 LeetCode110
左子树的高度和右子树的高度相差不超过1则称为平衡二叉树。
### 二叉搜索树 LeetCode98
#### 二叉搜索树 LeetCode98
递归解决
### 路径总和 LeetCode112
#### 路径总和 LeetCode112
### 达标路径总和 LeetCode113
#### 达标路径总和 LeetCode113
X是一棵二叉树的某一个节点A是二叉树先序遍历X的左边部分B是二叉树后序遍历X右边部分AB相交的结果是且仅是X的所有父节点。
1、X的所有父节点在先序遍历的左边X的所有父节点在后序遍历的右边交集一定包含所有父节点
2、X的所有子节点在先序遍历的左边X的所有子节点在后序遍历的左边交集一定不包含所有子节点
3、A不包含所有祖先节点的右兄弟节点B不包含所有祖先节点的左兄弟节点
X的所有祖先节点、X自己、X的子节点、X或者X的父节点作为左树的右兄节点、X或者X的父节点作为右树的左兄节点
判断二叉树是否是平衡二叉树
判断二叉树是否是搜索二叉树

@ -0,0 +1,66 @@
堆 大根堆、小根堆
完全二叉树的概念只有最下面一层,最右边当节点为空
最大线段重合问题
给定很多线段,每个线段都有两个数[start, end],表示线段开始位置和结束位置,左右都是闭区间
规定:
1线段的开始和结束位置一定都是整数值
2线段重合区域的长度必须>=1
返回线段最多重合区域中,包含了几条线段?
1、将所有线段按照start升序排序
2、构造堆保存当前重合所有重合线段的end, heap的size就是当前重合线段的数量
3、遍历所有线段如果出现不重合线段则弹出不重合的线段如果重合则加入end
手动改写堆(非常重要)!
系统提供的堆无法做到的事情:
1已经入堆的元素如果参与排序的指标方法变化系统提供的堆无法做到时间复杂度O(logN)调整都是O(N)的调整!
2系统提供的堆只能弹出堆顶做不到自由删除任何一个堆中的元素或者说无法在时间复杂度O(logN)内完成一定会高于O(logN)
根本原因:无反向索引表
手动改写堆的代码讲解
1建立反向索引表
2建立比较器
3核心在于各种结构相互配合非常容易出错
给定一个整型数组int[] arr和一个布尔类型数组boolean[] op
两个数组一定等长假设长度为Narr[i]表示客户编号op[i]表示客户操作
arr = [ 3 , 3 , 1 , 2, 1, 2, 5…
op = [ T , T, T, T, F, T, F…
依次表示3用户购买了一件商品3用户购买了一件商品1用户购买了一件商品2用户购买了一件商品1用户退货了一件商品2用户购买了一件商品5用户退货了一件商品…
一对arr[i]和op[i]就代表一个事件:
用户号为arr[i]op[i] == T就代表这个用户购买了一件商品
op[i] == F就代表这个用户退货了一件商品
现在你作为电商平台负责人,你想在每一个事件到来的时候,
都给购买次数最多的前K名用户颁奖。
所以每个事件发生后,你都需要一个得奖名单(得奖区)。
得奖系统的规则:
1如果某个用户购买商品数为0但是又发生了退货事件
则认为该事件无效得奖名单和上一个事件发生后一致例子中的5用户
2某用户发生购买商品事件购买商品数+1发生退货事件购买商品数-1
3每次都是最多K个用户得奖K也为传入的参数
如果根据全部规则得奖人数确实不够K个那就以不够的情况输出结果
4得奖系统分为得奖区和候选区任何用户只要购买数>0
一定在这两个区域中的一个
5购买数最大的前K名用户进入得奖区
在最初时如果得奖区没有到达K个用户那么新来的用户直接进入得奖区
6如果购买数不足以进入得奖区的用户进入候选区
7如果候选区购买数最多的用户已经足以进入得奖区
该用户就会替换得奖区中购买数最少的用户(大于才能替换),
如果得奖区中购买数最少的用户有多个,就替换最早进入得奖区的用户
如果候选区中购买数最多的用户有多个,机会会给最早进入候选区的用户
8候选区和得奖区是两套时间
因用户只会在其中一个区域,所以只会有一个区域的时间,另一个没有
从得奖区出来进入候选区的用户,得奖区时间删除,
进入候选区的时间就是当前事件的时间可以理解为arr[i]和op[i]中的i
从候选区出来进入得奖区的用户,候选区时间删除,
进入得奖区的时间就是当前事件的时间可以理解为arr[i]和op[i]中的i
9如果某用户购买数==0不管在哪个区域都离开区域时间删除
离开是指彻底离开,哪个区域也不会找到该用户
如果下次该用户又发生购买行为,产生>0的购买数
会再次根据之前规则回到某个区域中,进入区域的时间重记
请遍历arr数组和op数组遍历每一步输出一个得奖名单
public List<List<Integer>> topK (int[] arr, boolean[] op, int k)

@ -0,0 +1,2 @@
前缀树(prefix tree/trie tree)
前缀树是多叉树,便于处理字符串前缀相关的问题。

@ -0,0 +1,54 @@
# <center>设计模式概述</center>
<br />
### 编程方法论
&emsp;&emsp;编写高质量代码的方法论,包含面向对象、设计原则、设计模式、编程规范、重构技巧等
<br />
### 代码质量评价
&emsp;&emsp;可读性、可维护性、灵活性、简洁性、可复用性、可测试性、可扩展性。有很多工具可以做代码审计,评价代码的抽象、耦合程度。
<br />
### 六大设计原则
&emsp;&emsp;设计模式中主要有六大设计原则简称为SOLID是由于各个原则的首字母简称合并的来(两个L算一个,solid 稳定的)。
* 单一职责原则 Single Responsibitity Principle
* 开放封闭原则 Open Close Principle
* 里氏替换原则 Liskov Substitution Principle
* 接口隔离原则 Interface Segregation Principle
* 依赖倒转原则 Dependence Inversion Principle
* 迪米特法则 Least Knowledge Principle
<br />
### 设计模式
设计模式相关书籍,<设计模式:可复用面向对象软件的基础.pdf>
设计模式可大致分为三类,创建型、结构性、行为型。
![设计模式分类](./%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E5%88%86%E7%B1%BB.png)
<br />
### UML图
&emsp;&emsp;统一建模语言Unified Modeling LanguageUML是用来设计软件的可视化建模语言。它的特点是简单、统一、图形化、能表达软件设计中的动态与静态信息。
##### UML的分类
&emsp;&emsp;静态结构图: 类图、对象图、组件图、部署图
&emsp;&emsp;动态行为图: 状态图、活动图、时序图、协作图、构件图等。
在类的UML图中使用长方形描述一个类的主要构成长方形垂直地分为三层依次放置类的名称、属性和方法。+表示public、-表示private、#表示protected、不带符号表示默认修饰符。抽象类及抽象方法都用斜体字表示接口用&lt;&lt;Interfact&gt;&gt;表示。
##### UML类图中类关系的表述
*类实现接口 虚线、空心三角箭头
*泛化(单向、双向关联、自关联) 实线、空心三角箭头
*聚合(A持有BB在A的构造方法中new) 实线、空心方块
*组合(A持有BB为注入的对象) 实线、实心方块
*依赖(A对象的某个方法某个入参为B对象) 虚线、虚线箭头
<br />

@ -0,0 +1,24 @@
## 1、单例模式
### 定义
&emsp;&emsp;确保一个类只有一个实例,并提供一个全局访问点。
<br />
### 实现方式
* &emsp;饿汉式(也叫象牙塔IvoryTower),静态变量初始化实例保证线程安全
* &emsp;懒汉式,无法保证线程安全
* &emsp;双检查锁机制线程安全并保证并发量volatile关键字。
* &emsp;静态内部类
* &emsp;枚举方式jdk不能通过反射方式创建枚举实例反序列化通过枚举类名和枚举名称调用java.lang.Enum.valueOf(Class<T> enumType,String name)拿到枚举实例。
<br>
&emsp;&emsp;可以在私有的构造方法中添加非空判断并抛出异常阻止反射创建实例。添加readResolve()方法,返回单例对象,防止反序列化。
## 2、工厂方法
&emsp;&emsp;定义用于创建对象的接口但让子类决定实例化哪个类。工厂方法让类将实例化推迟到子类。所有子类创建的对象都实现同一个接口达到不同对象调用同一个方法实现不同的逻辑。可以使用枚举类和map保存不同类型的工厂。
![factory-method](./factory-method.urm.png)
&emsp;&emsp;简单工厂是工厂方法的特例。
&emsp;&emsp;用户只需要知道具体工厂的名字或者枚举值,就可以获取对应的对象,不需要关心对象的创建过程。在系统新增对象的时候,只需要添加具体对象的类和对应的具体工厂、枚举值,不需要对原工厂进行修改,满足了开闭原则。
&emsp;&emsp;每增加一个对象就需要一个具体的类,会增加系统的复杂度。

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

@ -0,0 +1,184 @@
# <center>Spring启动主要流程</center>
Spring框架源码版本5.3.x
![Spring Bean生命周期](Spring%20Bean%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.png)
### 框架源码的前置知识
* 设计模式
* 数据结构与算法
* 反射
* 多线程
* JVM
通过xml文件配置bean进行调试。
```xml
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" abstract="xxx" autowire="byName" autowire-candidate="default" depends-on="environment" init-method="afterPropertiesSet">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
</bean>
```
```Java
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml")
XXX xxbean = context.getBean(XXX.class);
xxbean.method();
context.close();
```
#### SSM框架项目中spring处理bean的主要流程
* 加载bean定义文件一般是xml文件或者注解
* 解析bean定义文件
* 封装BeanDefinition
* 处理PostProcessor
* 准备监听器
* 创建代理(JDK或者Cglib),使用反射实例化
* 属性填充和初始化
* 销毁
beanFactory容器使用map保存创建的bean,map的key和value内容
|序号| Key | Value |
|----| ---- | ---- |
|1| String | Object |
|2| Class | Object |
|3| String | ObjectFactory |
|4| String | BeanDefinition |
|4| String | lambda表达式 |
## Spring创建Bean过程中用到的主要接口和类
* BeanDefinitionReader
* BeanDefinition
* BeanFactory
* FactoryBean
* DefaultListableBeanFactory
* ClassPathXmlApplicationContext
* BeanPostProcessor
* BeanFactoryPostProcessor
* Aware
* BeanNameAware
* AbstractAutoProxyCreator
* ConfigurationClassPostProcessor
#### BeanDefinitionReader
&emsp;&emsp;指定带有Resource或者字符串参数的加载方法的bean definition的简单接口。根据定义格式(xml、properties、yaml、注解)具体的reader可以添加额外的加载和注册方法。
#### BeanDefinition
&emsp;&emsp;BeanDefinition描述带有属性值、构造器参数值、具体实现类的信息。
这是一个最小的接口主要使BeanFactoryPostProcessor可以自省和修改属性值和其他的bean元数据。
#### BeanFactory
&emsp;&emsp;访问Spring Bean容器的根接口。它是bean容器的基本客户端视图进一步的接口如ListableBeanFactory和ConfigurableBeanFactory可用于指定的目的。
&emsp;&emsp;这个接口被持有许多bean定义的对象实现每一个对象都由字符串唯一确定。依据bean定义factory将返回一个容器化对象的独立实例(原型设计模式),或者一个单例的共享对象(单例设计模式的一个更好的替代方案该实例在factory内部是单例的)。那种类型的实例会被返回依赖于factory的配置API是相同的。从Spring2.0开始,根据具体应用上下文,更多的范围可以被使用(比如web环境中的request和session)。
&emsp;&emsp;这种方法的要点是BeanFactory是应用程序组件的中央注册表并且集中了应用程序组件的配置(例如单个对象不再需要读取属性文件)。可以通过&lt;Expert One-on-One J2EE Design and Development&gt;的第4章和11章了解这种方式的优点。(到底是啥优点?)
&emsp;&emsp;一般来讲依靠DI(push配置)通过set或者构造方法配置应用对象是比使用任何形式比如查找BeanFactory拉取配置要好的。Spring的依赖注入功能是使用BeanFactory接口和它的子接口实现的。
&emsp;&emsp;通常一个BeanFactory将会加载保存在配置源(比如xml文档)中的bean定义使用org.springframework.beans包配置bean。但是实现可以简单地返回它根据需要直接在 Java 代码中创建的 Java 对象。bean定时可以被怎样储存是没有任何限制的可以使用LDAP、RDBMS、XML、properties文件等。鼓励实现支持 bean 之间的引用(依赖注入)。
&emsp;&emsp;与ListableBeanFactory中的方法相比如果它是一个HierarchicalBeanFactory这个接口的所有操作也会检查父工厂。如果一个bean没有在这个工厂实例中找到会在直接父工厂中查找。这个工厂实例中的 bean 应该覆盖任何父工厂中的同名 bean。
&emsp;&emsp;BeanFactory的实现类应该尽可能支持标准的bean生命周期接口。所有的初始化方法和顺序为
* BeanNameAware's {@code setBeanName}
* BeanClassLoaderAware's {@code setBeanClassLoader}
* BeanFactoryAware's {@code setBeanFactory}
* EnvironmentAware's {@code setEnvironment}
* EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
* ResourceLoaderAware's {@code setResourceLoader}
* ApplicationEventPublisherAware's {@code setApplicationEventPublisher} (only applicable when running in an application context)
* MessageSourceAware's {@code setMessageSource} (only applicable when running in an application context)
* ApplicationContextAware's {@code setApplicationContext} (only applicable when running in an application context)
* ServletContextAware's {@code setServletContext} (only applicable when running in an application context)
* {@code postProcessBeforeInitialization} methods of BeanPostProcessors (only applicable when running in a web application context)
* InitializingBean's {@code afterPropertiesSet}
* a custom {@code init-method} definition
* {@code postProcessAfterInitialization} methods of BeanPostProcessors
&emsp;&emsp;bean工厂关闭的时候会调用DestructionAwareBeanPostProcessors的postProcessBeforeDestruction()方法DisposableBean的destroy()方法自定义的destroy-method方法
#### FactoryBean
&emsp;&emsp;由BeanFactory中使用的对象实现的接口这些对象本身就是单个对象的工厂。 如果一个 bean 实现了这个接口,它就被用作一个对象的工厂来暴露,而不是直接作为一个将暴露自己的 bean 实例。
&emsp;&emsp;实现此接口的 bean 不能用作普通 bean。 FactoryBean 以 bean 样式定义,但为 bean 引用暴露的对象 getObject() 始终是它创建的对象。
&emsp;&emsp;FactoryBeans 可以支持单例和原型并且可以根据需要懒惰地创建对象也可以在启动时急切地创建对象。SmartFactoryBean接口允许公开更细粒度的行为元数据。
&emsp;&emsp;此接口在框架本身中大量使用,例如 AOP org.springframework.aop.framework.ProxyFactoryBean 或 org.springframework.jndi.JndiObjectFactoryBean。 它也可以用于自定义组件;但是,这仅适用于基础设施代码。
&emsp;&emsp;FactoryBean 是一个编程约定。实现不应该依赖于注解驱动的注入或其他反射设施。getObjectType() 和getObject() 调用可能在启动过程的早期到达,甚至在任何后处理器设置之前。 如果您需要访问其他 bean请实现BeanFactoryAware并以编程方式获取它们。
&emsp;&emsp;容器只负责管理 FactoryBean 实例的生命周期,而不负责管理 FactoryBean 创建的对象的生命周期。 因此,暴露的 bean 对象(例如 java.io.Closeable#close())上的 destroy 方法不会被自动调用。 相反FactoryBean 应该实现 DisposableBean 并将任何此类关闭调用委托给底层对象。
&emsp;&emsp;最后FactoryBean 对象参与包含 BeanFactory 的 bean 创建同步。 除了在 FactoryBean 本身(或类似的)中进行惰性初始化之外,通常不需要内部同步。
#### DefaultListableBeanFactory
&emsp;&emsp;Spring对ConfigurableListableBeanFactory和BeanDefinitionRegistry接口的默认实现基于 bean 定义元数据的成熟的 bean 工厂,可通过后处理器进行扩展。
&emsp;&emsp;典型用法是在访问bean前先注册所有 bean 定义(很可能是从一个bean定义文件中读取的)。在本地bean定义表中在预先解析的bean定义元数据上操作按照名称查找bean是一项廉价操作。
&emsp;&emsp;特定bean定义格式的reader都是被分开实现的而不是作为bean工厂的子类可以参考XmlBeanDefinitionReader。
&emsp;&emsp;对于ListableBeanFactory接口的替代实现可以参考StaticListableBeanFactory它管理已经存在的bean实例而不是根据bean定义创建新的bean。
#### ClassPathXmlApplicationContext
&emsp;&emsp;独立的 XML 应用程序上下文,从类路径中获取上下文定义文件,将普通路径解释为包含包路径的类路径资源名称(比如"mypackage/myresource.txt")。对于测试工具以及嵌入在 JAR 中的应用程序上下文很有用。
&emsp;&emsp;配置位置默认值可以通过 {@link #getConfigLocations} 覆盖,配置位置可以表示为具体文件,比如"myfiles/context.xml"或者Ant风格类型比如"myfiles/*-context.xml"(参考AntPathMatcher的java文档)。
&emsp;&emsp;注意:在多个配置位置的情况下,后面的 bean 定义将覆盖前面加载文件中定义的那些。 这可以用来通过额外的 XML 文件故意覆盖某些 bean 定义。
&emsp;&emsp;这是一个简单的、一站式便利的 ApplicationContext。考虑使用GenericApplicationContext类结合XmlBeanDefinitionReader进行更灵活的上下文设置。
#### BeanPostProcessor
&emsp;&emsp;允许自定义修改新 bean 实例的工厂钩子——例如,检查标记接口或使用代理包装 bean。
&emsp;&emsp;通常后处理器通过标记接口填充bean或类似的将实现{@link #postProcessBeforeInitialization},而用代理包装 bean 的后处理器通常会实现{@link #postProcessAfterInitialization}。
&emsp;&emsp;ApplicationContext可以在其 bean 定义中自动检测 BeanPostProcessor bean并将这些后处理器应用于随后创建的任何 bean。普通的 BeanFactory 允许后处理器的编程注册,将它们应用于通过 bean 工厂创建的所有 bean。
&emsp;&emsp;在 ApplicationContext 中自动检测到的 BeanPostProcessor bean 将根据 org.springframework.core.PriorityOrdered 和 org.springframework.core.Ordered 语义进行排序。相反,使用 BeanFactory 以编程方式注册的 BeanPostProcessor bean 将按注册顺序应用;对于以编程方式注册的后处理器,将忽略通过实现 PriorityOrdered 或 Ordered 接口表达的任何排序语义。此外, org.springframework.core.annotation.Order @Order 注解没有被考虑用于 BeanPostProcessor bean。
#### BeanFactoryPostProcessor
&emsp;&emsp;允许自定义修改应用程序上下文的 bean 定义的工厂钩子,调整上下文底层 bean 工厂的 bean 属性值。
&emsp;&emsp;对于针对系统管理员的自定义配置文件很有用,这些配置文件会覆盖在应用程序上下文中配置的 bean 属性。 请参阅 {@link PropertyResourceConfigurer} 及其具体实现,以了解满足此类配置需求的现成解决方案。
&emsp;&emsp;BeanFactoryPostProcessor 可以与 bean 定义交互并修改 bean 定义,但绝不能与 bean 实例交互。 这样做可能会导致 bean 过早实例化,违反容器并导致意外的副作用。 如果需要 bean 实例交互,请考虑改为实施 BeanPostProcessor。
&emsp;&emsp;ApplicationContext 自动检测其 bean 定义中的 BeanFactoryPostProcessor bean并在创建任何其他 bean 之前应用它们。 BeanFactoryPostProcessor 也可以通过 ConfigurableApplicationContext} 以编程方式注册。
&emsp;&emsp;在 ApplicationContext 中自动检测到的 BeanFactoryPostProcessor bean 将根据 org.springframework.core.PriorityOrdered 和 org.springframework.core.Ordered 语义进行排序。 相反,使用 ConfigurableApplicationContext 以编程方式注册的 BeanFactoryPostProcessor beans 将按注册顺序应用; 对于以编程方式注册的后处理器,将忽略通过实现 PriorityOrdered 或 Ordered 接口表达的任何排序语义。 此外, org.springframework.core.annotation.Order @Order 注释未被考虑用于 BeanFactoryPostProcessor beans。
#### Aware
&emsp;&emsp;一个标记父接口,指示一个 bean 有资格通过回调样式的方法被特定框架对象的 Spring 容器通知。 实际的方法签名由各个子接口确定,但通常应该只包含一个接受单个参数的返回 void 的方法。
&emsp;&emsp;请注意,仅实现 Aware 不提供默认功能。相反,处理必须显式完成,例如在 org.springframework.beans.factory.config.BeanPostProcessor 中。 有关处理特定 *Aware 接口回调的示例,请参阅 org.springframework.context.support.ApplicationContextAwareProcessor。
#### BeanNameAware
&emsp;&emsp;由想要在 bean 工厂中了解其 bean 名称的 bean 实现的接口。 请注意,通常不建议对象依赖于其 bean 名称,因为这表示对外部配置的潜在脆弱依赖,以及对 Spring API 的可能不必要的依赖。
#### AbstractAutoProxyCreator
&emsp;&emsp;org.springframework.beans.factory.config.BeanPostProcessor 的实现,用 AOP 代理包装每个符合条件的 bean在调用 bean 本身之前委托给指定的拦截器。
&emsp;&emsp;这个类区分“通用”拦截器:为它创建的所有代理共享,以及“特定”拦截器:每个 bean 实例唯一。不需要任何公共拦截器。如果有,则使用 interceptorNames 属性设置它们。 与 org.springframework.aop.framework.ProxyFactoryBean 一样,使用当前工厂中的拦截器名称而不是 bean 引用来允许正确处理原型顾问程序和拦截器:例如,支持有状态混合。#setInterceptorNames "interceptorNames" 条目支持任何建议类型。
&emsp;&emsp;如果有大量的 beans 需要用类似的代理包装,即委托给相同的拦截器,那么这种自动代理特别有用。 您可以向 bean 工厂注册一个这样的后处理器,而不是为 x 个目标 bean 重复定义 x 个代理,以达到相同的效果。
&emsp;&emsp;子类可以应用任何策略来决定是否要代理一个 bean例如 按类型、按名称、按定义详细信息等。它们还可以返回应仅应用于特定 bean 实例的其他拦截器。 一个简单的具体实现是 {@link BeanNameAutoProxyCreator},通过给定名称识别要代理的 bean。
&emsp;&emsp;可以使用任意数量的 TargetSourceCreator 实现来创建自定义目标源:例如,池化原型对象。 即使没有建议,自动代理也会发生,只要 TargetSourceCreator 指定自定义 org.springframework.aop.TargetSource。 如果没有设置 TargetSourceCreators或者没有匹配项默认情况下将使用 org.springframework.aop.target.SingletonTargetSource 来包装目标 bean 实例。
#### ConfigurationClassPostProcessor
&emsp;&emsp;启动过程中处理@Configuration注解。通过\<context:annotation-config/>或者\<context:component-scan/>标签注册也可以通过其他BeanFactoryPostProcessor手动注册。他实现了PriorityOrdered接口@Configuration注解修饰的类中所有具有bean定义的方法在所有BeanFactoryPostProcessor执行之前注册。

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 KiB

@ -1,162 +0,0 @@
### 框架源码的前置知识
* 设计模式
* 数据结构与算法
* 反射
* 多线程
* JVM
IOC控制反转
DI依赖注入
```xml
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" abstract="xxx" autowire="byName" autowire-candidate="default" depends-on="environment" init-method="afterPropertiesSet">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
</bean>
```
```Java
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml")
XXX xxbean = context.getBean(XXX.class);
xxbean.method();
```
#### SSM框架项目中spring处理bean的主要流程
* 加载xml文件
* 解析xml文件
* 封装BeanDefinition
* 实例化
* 放到容器中
* 从容器中获取
容器使用map保存bean,map的key和value内容
|序号| Key | Value |
|----| ---- | ---- |
|1| String | Object |
|2| Class | Object |
|3| String | ObjectFactory |
|4| String | BeanDefinition |
## Spring创建Bean过程中用到的主要接口
* BeanDefinitionReader
* BeanDefinition
* BeanFactory
* FactoryBean
* DefaultListableBeanFactory
* ClassPathXmlApplicationContext
* BeanPostProcessor
* BeanFactoryPostProcessor
* Aware
* BeanNameAware
* AbstractAutoProxyCreator
#### BeanDefinitionReader
指定带有Resource或者字符串参数的加载方法的bean definition的简单接口。根据定义格式(xml、properties、yaml、注解)具体的reader可以添加额外的加载和注册方法。
#### BeanDefinition
BeanDefinition描述带有属性值、构造器参数值、具体实现类的信息。
这是一个最小的接口主要使BeanFactoryPostProcessor可以自省和修改属性值和其他的bean元数据。
#### BeanFactory
访问Spring Bean容器的根接口。它是bean容器的基本客户端视图进一步的接口如ListableBeanFactory和ConfigurableBeanFactory可用于指定的目的。
这个接口被持有许多bean定义的对象实现每一个对象都由字符串唯一确定。依据bean定义factory将返回一个容器化对象的独立实例(原型设计模式),或者一个单例的共享对象(单例设计模式的一个更好的替代方案该实例在factory内部是单例的)。那种类型的实例会被返回依赖于factory的配置API是相同的。从Spring2.0开始,根据具体应用上下文,更多的范围可以被使用(比如web环境中的request和session)。
这种方法的要点是BeanFactory是应用程序组件的中央注册表并且集中了应用程序组件的配置(例如单个对象不再需要读取属性文件)。可以通过&lt;Expert One-on-One J2EE Design and Development&gt;的第4章和11章了解这种方式的优点。(到底是啥优点?)
一般来讲依靠DI(push配置)通过set或者构造方法配置应用对象是比使用任何形式比如查找BeanFactory拉取配置要好的。Spring的依赖注入功能是使用BeanFactory接口和它的子接口实现的。
通常一个BeanFactory将会加载保存在配置源(比如xml文档)中的bean定义使用org.springframework.beans包配置bean。但是实现可以简单地返回它根据需要直接在 Java 代码中创建的 Java 对象。bean定时可以被怎样储存是没有任何限制的可以使用LDAP、RDBMS、XML、properties文件等。鼓励实现支持 bean 之间的引用(依赖注入)。
与ListableBeanFactory中的方法相比如果它是一个HierarchicalBeanFactory这个接口的所有操作也会检查父工厂。如果一个bean没有在这个工厂实例中找到会在直接父工厂中查找。这个工厂实例中的 bean 应该覆盖任何父工厂中的同名 bean。
BeanFactory的实现类应该尽可能支持标准的bean生命周期接口。所有的初始化方法和顺序为
* BeanNameAware's {@code setBeanName}
* BeanClassLoaderAware's {@code setBeanClassLoader}
* BeanFactoryAware's {@code setBeanFactory}
* EnvironmentAware's {@code setEnvironment}
* EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
* ResourceLoaderAware's {@code setResourceLoader}
* ApplicationEventPublisherAware's {@code setApplicationEventPublisher} (only applicable when running in an application context)
* MessageSourceAware's {@code setMessageSource} (only applicable when running in an application context)
* ApplicationContextAware's {@code setApplicationContext} (only applicable when running in an application context)
* ServletContextAware's {@code setServletContext} (only applicable when running in an application context)
* {@code postProcessBeforeInitialization} methods of BeanPostProcessors (only applicable when running in a web application context)
* InitializingBean's {@code afterPropertiesSet}
* a custom {@code init-method} definition
* {@code postProcessAfterInitialization} methods of BeanPostProcessors
bean工厂关闭的时候会调用DestructionAwareBeanPostProcessors的postProcessBeforeDestruction()方法DisposableBean的destroy()方法自定义的destroy-method方法
#### FactoryBean
#### DefaultListableBeanFactory
Spring对ConfigurableListableBeanFactory和BeanDefinitionRegistry接口的默认实现基于 bean 定义元数据的成熟的 bean 工厂,可通过后处理器进行扩展。
典型用法是在访问bean前先注册所有 bean 定义(很可能是从一个bean定义文件中读取的)。在本地bean定义表中在预先解析的bean定义元数据上操作按照名称查找bean是一项廉价操作。
特定bean定义格式的reader都是被分开实现的而不是作为bean工厂的子类可以参考XmlBeanDefinitionReader。
对于ListableBeanFactory接口的替代实现可以参考StaticListableBeanFactory它管理已经存在的bean实例而不是根据bean定义创建新的bean。
#### ClassPathXmlApplicationContext
独立的 XML 应用程序上下文,从类路径中获取上下文定义文件,将普通路径解释为包含包路径的类路径资源名称(比如"mypackage/myresource.txt")。对于测试工具以及嵌入在 JAR 中的应用程序上下文很有用。
配置位置默认值可以通过 {@link #getConfigLocations} 覆盖,配置位置可以表示为具体文件,比如"myfiles/context.xml"或者Ant风格类型比如"myfiles/*-context.xml"(参考AntPathMatcher的java文档)。
注意:在多个配置位置的情况下,后面的 bean 定义将覆盖前面加载文件中定义的那些。 这可以用来通过额外的 XML 文件故意覆盖某些 bean 定义。
这是一个简单的、一站式便利的 ApplicationContext。考虑使用GenericApplicationContext类结合XmlBeanDefinitionReader进行更灵活的上下文设置。
#### BeanPostProcessor
允许自定义修改新 bean 实例的工厂钩子——例如,检查标记接口或使用代理包装 bean。
通常后处理器通过标记接口填充bean或类似的将实现{@link #postProcessBeforeInitialization},而用代理包装 bean 的后处理器通常会实现{@link #postProcessAfterInitialization}。
ApplicationContext可以在其 bean 定义中自动检测 BeanPostProcessor bean并将这些后处理器应用于随后创建的任何 bean。普通的 BeanFactory 允许后处理器的编程注册,将它们应用于通过 bean 工厂创建的所有 bean。
在 {@code ApplicationContext} 中自动检测到的 {@code BeanPostProcessor} bean 将根据 {@link org.springframework.core.PriorityOrdered} 和 {@link org.springframework.core.Ordered} 语义进行排序。相反,使用 {@code BeanFactory} 以编程方式注册的 {@code BeanPostProcessor} bean 将按注册顺序应用;对于以编程方式注册的后处理器,将忽略通过实现 {@code PriorityOrdered} 或 {@code Ordered} 接口表达的任何排序语义。此外,{@link org.springframework.core.annotation.Order @Order} 注解没有被考虑用于 {@code BeanPostProcessor} bean。
#### BeanFactoryPostProcessor
允许自定义修改应用程序上下文的 bean 定义的工厂钩子,调整上下文底层 bean 工厂的 bean 属性值。
对于针对系统管理员的自定义配置文件很有用,这些配置文件会覆盖在应用程序上下文中配置的 bean 属性。 请参阅 {@link PropertyResourceConfigurer} 及其具体实现,以了解满足此类配置需求的现成解决方案。
{@code BeanFactoryPostProcessor} 可以与 bean 定义交互并修改 bean 定义,但绝不能与 bean 实例交互。 这样做可能会导致 bean 过早实例化,违反容器并导致意外的副作用。 如果需要 bean 实例交互,请考虑改为实施 {@link BeanPostProcessor}。
{@code ApplicationContext} 自动检测其 bean 定义中的 {@code BeanFactoryPostProcessor} bean并在创建任何其他 bean 之前应用它们。 {@code BeanFactoryPostProcessor} 也可以通过 {@code ConfigurableApplicationContext} 以编程方式注册。
在 {@code ApplicationContext} 中自动检测到的 {@code BeanFactoryPostProcessor} bean 将根据 {@link org.springframework.core.PriorityOrdered} 和 {@link org.springframework.core.Ordered} 语义进行排序。 相反,使用 {@code ConfigurableApplicationContext} 以编程方式注册的 {@code BeanFactoryPostProcessor} beans 将按注册顺序应用; 对于以编程方式注册的后处理器,将忽略通过实现 {@code PriorityOrdered} 或 {@code Ordered} 接口表达的任何排序语义。 此外,{@link org.springframework.core.annotation.Order @Order} 注释未被考虑用于 {@code BeanFactoryPostProcessor} beans。
#### Aware
一个标记父接口,指示一个 bean 有资格通过回调样式的方法被特定框架对象的 Spring 容器通知。 实际的方法签名由各个子接口确定,但通常应该只包含一个接受单个参数的返回 void 的方法。
请注意,仅实现 {@link Aware} 不提供默认功能。相反,处理必须显式完成,例如在 {@link org.springframework.beans.factory.config.BeanPostProcessor} 中。 有关处理特定 {@code *Aware} 接口回调的示例,请参阅 {@link org.springframework.context.support.ApplicationContextAwareProcessor}。
#### BeanNameAware
由想要在 bean 工厂中了解其 bean 名称的 bean 实现的接口。 请注意,通常不建议对象依赖于其 bean 名称,因为这表示对外部配置的潜在脆弱依赖,以及对 Spring API 的可能不必要的依赖。
#### AbstractAutoProxyCreator
{@link org.springframework.beans.factory.config.BeanPostProcessor} 的实现,用 AOP 代理包装每个符合条件的 bean在调用 bean 本身之前委托给指定的拦截器。
这个类区分“通用”拦截器:为它创建的所有代理共享,以及“特定”拦截器:每个 bean 实例唯一。不需要任何公共拦截器。如果有,则使用 interceptorNames 属性设置它们。 与 {@link org.springframework.aop.framework.ProxyFactoryBean} 一样,使用当前工厂中的拦截器名称而不是 bean 引用来允许正确处理原型顾问程序和拦截器:例如,支持有状态混合。 {@link #setInterceptorNames "interceptorNames"} 条目支持任何建议类型。
如果有大量的 beans 需要用类似的代理包装,即委托给相同的拦截器,那么这种自动代理特别有用。 您可以向 bean 工厂注册一个这样的后处理器,而不是为 x 个目标 bean 重复定义 x 个代理,以达到相同的效果。
子类可以应用任何策略来决定是否要代理一个 bean例如 按类型、按名称、按定义详细信息等。它们还可以返回应仅应用于特定 bean 实例的其他拦截器。 一个简单的具体实现是 {@link BeanNameAutoProxyCreator},通过给定名称识别要代理的 bean。
可以使用任意数量的 {@link TargetSourceCreator} 实现来创建自定义目标源:例如,池化原型对象。 即使没有建议,自动代理也会发生,只要 TargetSourceCreator 指定自定义 {@link org.springframework.aop.TargetSource}。 如果没有设置 TargetSourceCreators或者没有匹配项默认情况下将使用 {@link org.springframework.aop.target.SingletonTargetSource} 来包装目标 bean 实例。
Loading…
Cancel
Save