数据结构
数组
Array、Array List...
特点
char[] cs = new char[5];
char[] cs2 = new char[]{'fish','bone'};
cs[0] = "fish";
...
- 内存地址连续,使用前需要指定数组长度。
- 有下标。依据下标来获取、设置值。查询效率高。
- 增删操作效率较低。(需要考虑下标越界问题,动态扩缩容)
总结
增删操作效率较低主要指:
- 新增。
- 初始长度假如是5,不停的新增,当增加到第6个元素时,则需要从触发扩容操作(一般会提前触发不会等数组满了才触发),扩容操作则需要重新建立一个数组,将之前数据中元素移动过来。
- 初始长度范围内的新增效率很高。
- 修改。
- 如果要修改某个元素,比如将数组中'bone'修改为‘bones’则需要遍历查抄,然后修改。
- 直接通过下标修改效率比较高。
- 删除。
- 如果删除虽然元素不在,但是内存依然存在,且空间是连续的。比较占用内存。
综上所述,数组适用于,查询操作较多。修改、新增、删除操作较少的定长数据情况。
链表
单向链表|双向链表(Linked List)
特点
- 灵活的空间要求,存储空间不要求连续。
- 不支持下标访问,查询效率低,支持顺序遍历检索(next)。
- 针对增删操作效率会比较高,只需要操作节点,无需移动元素。
总结
链表适合于新增,删除操作较多的情况,由于无法通过下标快速获取到某个位置元素,所以对查询操作不够友好。
数组、链表问题
-
在连续新增100W条数据的情况下,ArrayList和LinkedList哪一个效率更快?为什么?
- 错误回答:LinkedList,因为他是链表结构,链表接口新增效率高。ArrayList是数组接口,新增慢。
- 分析:这个问题主要考虑理解深度,不能简单因为链表新增快就回答LinkedList。所有的快慢都是需要分情况的。
- 正确回答: ArrayList效率高。因为LinkedList每次新增都要new Node()节点。此外还需要操作prev、next两个节点。而ArrayList如果初始就把长度固定则不需要创建那么多对象出来。所以数组的效率就要高于链表。
public static void main(String[] args) {
long startTime=System.currentTimeMillis(); //获取开始时间
arrayTest();
long endTime=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间1: "+(endTime-startTime)+"ms");
long startTime1 = System.currentTimeMillis(); //获取开始时间
linkTest();
long endTime1 = System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间2: "+(endTime1-startTime1)+"ms");
}
private static void linkTest() {
LinkedList linkedList = new LinkedList();
for(int i=0;i<1000000;i++){
linkedList.add(i);
}
}
private static void arrayTest() {
ArrayList array = new ArrayList(1000000);
for(int i=0;i<1000000;i++){
array.add(i);
}
}
// 执行结果
程序运行时间1: 18ms
程序运行时间2: 28ms
Process finished with exit code 0
树(Tree)
二叉树
只有左右两个叉的树结构。
二叉树中包含:
- 平衡二叉树
- 不平衡二叉树
- 完全平衡二叉树
- 不完全平衡二叉树(红黑树)。
特点
- 某节点的左侧树节点值仅包含小于该节点的值。
- 某节点的右侧树节点值仅包含大于该节点的值。
- 左右树节点每个也必须是二叉树。
- 顺序排列。
红黑树
自平衡二叉树。(黑平衡二叉树)
特点
- 每个节点要么是红,要么是黑。
- 根节点必须是黑色。
- 每个叶子节点【NIL】必须是黑色。
- 每个红色节点的子节点必须是黑色。
- 任意节点向下到任意叶子节点【NIL】的路径包含相同数量的黑色节点(黑平衡二叉树)。
BTree
平衡多路查找树,节点不只是2个。
每个节点都会存储数据。
B+Tree
1kb = 1024b , 1字节 = 8 位。 UUID 32位
平衡多路查找树,节点不只是2个。
是对BTree的优化,数据仅存储在叶子结点,且叶子节点以链表的形式存在。
集合
TreeMap
特点
- 本质是红黑树的实现
- 有序的
HashMap
数组+链表。数组+红黑树
链表数据长度>8的时候转化为红黑树。
HashSet
HashSet底层是HashMap,本质是一个没有重复元素的集合,通过hashmap实现。
HashSet hashSet = new HashSet();
hashSet.add(1);
//源码
public HashSet(){
map = new HashMap<>();
}
public boolean add(E e){
return map.put(e,PRESENT)==null;
}
TreeSet
TreeSet底层是TreeMap,本质是将数据保存在TreeMap中,key为添加的数据,value是一个固定的值。
Spring
Spring 特点
Spring 主要为了使开发人员能够更专注也业务本身,尽可能的减少其他非业务的东西而出现。
为了实现他这个目的,Spring 一方面提供了三大核心功能(IOC,DI,AOP)帮助开发人员管理Bean的生命周期。
另一方面 将自己变成一个万能胶,利用自身提供的一些扩展点,能够对市面上的大部分框架和中间建进行集成,方便使用。
同时也不断的优化自身,从最开始的XML到现在的注解一切都是为了方便开发人员,提高开发效率。
IOC(控制反转)
Spring的IOC主要是为了实现对Bean的统一管理,将Bean的初始化、创建,销毁都交由Spring的IOC容器来实现。
BeanFactory(IOC容器的定义类)
1. 对IOC的基本行为做了定义。(getBean,constainsBean,isSingleton,isPropotype,isTypeMatch,getType)
2. 主要实现类ListableBeanFactory、HierarchialBeanFactory(有继承关系)、AutowireCapableBeanFactory定义自动装配规则。
3. 最终实现类是DefaultListableBeanFactory,该类包含beanDefinitionMap等集合。
ApplicationContext(高级的IOC容器)
1. 除了提供IOC容器的基本操作外(AbstractApplicationContext)还提供了一些附加功能。
2. 主要实现类ClassPathXMLApplicaitonContext、AnnotationConfigApplicaitonContext
BeanDefinition
1. Bean对象的描述类,描述了Bean对象的基本信息以及相互关系(类名、作用域、属性、依赖关系)。
2. 主要实现类AbstuctBeanDefinition、RootBeanDefinition、GenericBeanDenifition。
BeanDefinitionReader
1. Bean对象的解析类。
2. AbstractBeanDefinitionReader、XmlBeanDefinitionReader、PropertiesBeanDefinitionReader
IOC的过程实际是为了完成BeanDefinition的注册,放在beanDefinitionMap中。
首先这个过程中初始化的配置定义是多样的,有XML、注解等,所以需要使用不同的策略来去读取。这里就包含两个主要的核心类ClassPathXMLApplicaitonContext、AnnotationConfigApplicaitonContext,以及对应的解析器XmlBendifinitionReader、AnnotatedBeanDefinitionReader,为了方便管理又使用了BeanDefinition来统一配置标准。
他的核心流程大概分为三个阶段:定位—》加载—》注册。
Web IOC为例:
org.springframework.web.context.ContextLoaderListener
dispatcherServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath*:/spring-mvc.xml
1
首先从web.xml配置的DispatcherServlet为起点(tomcat启动时也会调用ContextLoaderListener类contextInitialized方法),首先调用HttpServlet类的init()方法,init()方法或者contextInitialized()中会调用initWebApplicationContext方法,进行初始化,然后会调用到AbstractApplicationContext的refresh()方法,这个也是Spring的核心类。refresh()方法中会调用obtainFreshBeanFactory()来完成IOC容器的注册和依赖注入。在obtainFreshBeanFactory()方法中会调用子类的refreshBeanFactory()方法,进行creatBeanFactory()、loadBeanDefinitions()、doLoadBeanDefinition()、registerBeanDefinition()、doRegisterBeanDefinitions()最终调用的是DefaultListableBeanFactory类的registerBeanDefinition()方法来完成Bean的注册。
DI
BeanWrapper( Bean的包装,包含Bean的属性、方法,数据 )
核心流程大致分为两个阶段:实例化-》依赖注入
DI操作由BeanFactory的getBean()方法开始,实际调用的是AbstructBeanFactoty()的getBean()方法,在这里会直接进行doGetBean()的操作。在doGetBean()方法中需要调用一个getSingleton()方法,该方法参数需要一个函数接口,最终调用的是函数接口实现的creatBean方法AbstractAutowireCapableBeanFactory类(多例的会直接调用creatBean方法),然后会调用doCreateBean()方法,在这会实例化BeanWrapper对象,这里边有几个核心方法createBeanInstance()创建bean实例,addSingletonFactory向容器中缓存单例模式的Bean对象,以防循环依赖,populateBean并将Bean实例对象封装,并且执行DI操作,填充Bean属性。initializeBean执行一些BeanPostProcessor,Before,After处理、AOP,以及InitializingBean的afterPropertiesSet方法。
循环依赖
思考:什么是值传递?什么是引用传递?
Spring中解决循环依赖其实是利用了引用传递的特性,允许对象初始化未填充属性阶段先让其他依赖对象完成引用,后续再赋值。
问题:
哪些情况可以解决?哪些不可以解决?
- 构造函数循环依赖。(NO)
- 多例Prototype Field Setter 类型循环依赖。(NO)
- 单例Singleton Field Setter 类型循环依赖。(Yes)
Spring 如何解决循环依赖
Spring在解决循环依赖问题时,主要通过三级缓存,利用引用传递的特性。在依赖注入之前,将A未完成初始化的bean放入第三级缓存中,key>(ObjectFactory为函数式接口实现,调用getEarlyBeanReference方法),执行DI操作时需要完成B对象实例化,B对象执行DI操作依赖A时,可以直接从三级缓存中获取到未完成的A对象完成B对象的实例化过程,由于引用传递,后续A对象在实例化完成后,B对象中的A对象也完成实例操作。
假如A依赖B,B依赖A,此时先初始化A:
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
//真正实现向IOC容器获取Bean的功能,也是触发依赖注入功能的地方
protected T doGetBean(final String name, @Nullable final Class requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//如果指定的是别名,将别名转换为规范的Bean名称
final String beanName = transformedBeanName(name);
Object bean;
// 先从缓存中取是否已经有被创建过的单态类型的Bean
// 对于单例模式的Bean整个IOC容器中只创建一次,不需要重复创建
// 此时A 明显获取不到A 对象
// 当此时为实例化B,为B实例注入A对象调用doGetBean(A)方法情况时,则可以拿到A对象,然后返回,具体看最下方代码
Object sharedInstance = getSingleton(beanName);
//IOC容器创建单例模式Bean实例对象
if (sharedInstance != null && args == null) {
// 省略...
}
else {
// 省略 ...
try {
if (mbd.isSingleton()) {
//这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
sharedInstance = getSingleton(beanName, () -> {
try {
//创建一个指定Bean实例对象,如果有父级继承,则合并子类和父类的定义
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//显式地从容器单例模式Bean缓存中清除实例对象
destroySingleton(beanName);
throw ex;
}
});
//获取给定Bean的实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
}
...
return (T) bean;
}
}
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
// ...
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// ...
beforeSingletonCreation(beanName);
// ...
try {
// 调用函数式接口getObject()实现方法,等价于 createBean(beanName, mbd, args);
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
}
finally {
// 执行后续方法
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
}
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
//真正创建Bean的方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
//封装被创建的Bean对象
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 创建实例(此时未赋值属性)
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 获得过早曝光对象bean。
final Object bean = instanceWrapper.getWrappedInstance();
// ...
//向容器中缓存单例模式的Bean对象,以防循环引用
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
//向第三级缓存添加 对象实例
//同时生成 函数接口实现,一并添加到singletonObjects中,后续会调用。
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
//protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {
// Assert.notNull(singletonFactory, "Singleton factory must not be null");
// synchronized (this.singletonObjects) {
// if (!this.singletonObjects.containsKey(beanName)) {
// this.singletonFactories.put(beanName, singletonFactory);
// this.earlySingletonObjects.remove(beanName);
// this.registeredSingletons.add(beanName);
// }
// }
//}
}
// Initialize the bean instance.
//Bean对象的初始化,依赖注入在此触发
//这个exposedObject在初始化完成之后返回作为依赖注入完成后的Bean
Object exposedObject = bean;
try {
//将Bean实例对象封装,并且Bean定义中配置的属性值赋值给实例对象
// 此时发现A依赖于B,回去执行B的getBean(),然后同A初始化.
// 在B实例化到此处时,发现B引用了A实例,那么就会尝试获取A实例对象(调用getBean(A)方法)。
populateBean(beanName, mbd, instanceWrapper);
//初始化Bean对象
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
//获取指定名称的已注册的单例模式Bean对象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
//根据名称获取的已注册的Bean和正在实例化的Bean是同一个
if (exposedObject == bean) {
//当前实例化的Bean初始化完成
exposedObject = earlySingletonReference;
}
//当前Bean依赖其他Bean,并且当发生循环引用时不允许新创建实例对象
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
}
}
}
// Register bean as disposable.
//注册完成依赖注入的Bean
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
}
//DefaultSingletonBeanRegistry
//Spring利用三级缓存来解决循环依赖,singletonObjects(1),earlySingletonObjects(2),singletonFactories(3),
// singletonsCurrentlyInCreation 这个缓存也非常重要,在bean开始创建时存入,创建完成后移除,只存储正在创建中的bean。
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 用于存储完全实例化好的bean 对象。
// 首先尝试从实例化好缓存中 获取对象 此时(循环依赖情况)肯定获取不到。
Object singletonObject = this.singletonObjects.get(beanName);
// 追加判断 该对象正在创建中(是的)
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 未创建完成,提前曝光的bean对象,用于解决循环依赖
// 尝试从提前曝光的Bean中获取对象,对于 初始化A(A依赖B,B依赖A) 显然获取不到A对象
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 尝试再从三级缓存单例工厂中获取,此时A(A依赖B,B依赖A)很明显也获取不到。 返回null.
// 此时为初始化A对象(在A对象初始化中,发现依赖B,初始化B,发现B依赖A,然后尝试获取A对象情况
// 能够从singletonFactory中拿到A对象。
// addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 这里 getObject()方法,实际调用getEarlyBeanReference(beanName, mbd, bean)
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
//AbstractAutowireCapableBeanFactory
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
Aop
Aop核心
- 切面 Aspect,面向规则,具有相同规则的方法 (methonCache)集合。
- 通知 Advice,调用(回调)操作。
- 切点 PointCurd,需要代理的具体方法。
- 目标对象 Target,需要代理的对象()。
- 代理 Proxy,JDK ,CGLIB。
- 前置通知、后置通知、异常通知。
概述
简单来说,AOP就是通过一定的规则,来当做切面。在Spring 实例化DI阶段,基于规则判断是否满足,满足则使用代理来代替目标对象。在使用代理对象,调用方法时,会从methodCache中获取后续执行链(chain),如果存在,则表示改方法有AOP代理需求,执行后续链操作。如果没有直接利用反射调用目标类方法。
在chain不为null时,Spring 使用责任链模式,来执行操作(有一定的执行顺序)。
// 缓存切点 拦截器
Map> methodCache;
注意
AOP是基于一定的规则来匹配方法(通过拦截器实现),是方法层面的代理和织入。但是由于代理针对的是类,所以在DI操作进行规则验证时,只需要验证类的层面满足就可以。在生成代理对象后调用方法时,才会对方法层面进行验证(chain),通过反射来实现方法的调用。
AOP采用策略模式,使用JDK(有实现接口时),和CGLIB两种方式来实现代理。
-
AOP操作的开始点是在DI执行之后。
populateBean(beanName, mbd, instanceWrapper);
//初始化Bean对象
// 包含AOP 初始化,AOP属于后置处理。 实现了 BeanPostProcessor接口。
exposedObject = initializeBean(beanName, exposedObject, mbd);
//AOP 代理类
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
}
MVC
Spring扩展点
InitializingBean 类
// 在完成bean 的注入(populateBean())之后 调用
// 针对单个bean使用。
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
调用流程见BeanPostProcessor 类。
BeanPostProcessor 类
public interface BeanPostProcessor {
//在Bean 完成定义BeanDefinition、完成依赖注入getBean()->populateBean(),调用无参构造函数完成实例化前执行
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
//在Bean 完成定义BeanDefinition、完成依赖注入getBean(),调用无参构造函数完成实例化后执行。
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// 所有的类都会触发
}
调用详解
//AbstractAutowireCapableBeanFactory
// getBean() 流程
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// ... 省略 无关代码
// Instantiate the bean.
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 这里处理 特殊的 MergedBeanDefinitionPostProcessor
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 这里完成 bean 初始化DI 工作
populateBean(beanName, mbd, instanceWrapper);
// 这里 initializeBean 方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
// ... 省略无关代码
return exposedObject;
}
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction