IOC
- 控制:指的是对象创建(实例化、管理)的权力
- 反转:控制权交给外部环境(Spring 框架、IoC 容器)
AOP
动态代理
JDK动态代理:
- 创建一个接口及其实现类
- 自定义handler,重写invoke方法,在方法里面调用原逻辑,并增加额外逻辑
- 通过代理类创建代理对象
CGLIB动态代理
- 定义一个类
- 自定义拦截器,重写拦截方法,用于增强原有方法
- 通过Enhancer类创建代理类(实际上是通过创建子类实现,如果是final类就不能使用CGLIB
实现步骤:
- 自定义一个切点,包含生效阶段(source, class, runtime
- 定义一个切面
AspectJ:属于静态织入,实际运行之前就完成了织入
BeanFactory
是spring框架的基础设施,面向spring本身。是类的通用工厂,可以创建并管理各种类的对象。
Application Context建立在BeanFactory的基础上,面向使用spring框架的开发者
Spring容器启动阶段的任务
分为两个阶段:
- 容器启动阶段:加载和解析配置文件,保存到对应的bean定义中
- Bean实例化阶段
Bean的生命周期
- 实例化阶段:在容器中创建Bean的实例,并调用Bean的构造方法,将其实例化
- 属性设置阶段:调用相应的set方法,属性会被设置成默认值或者通过配置文件提供的值
- 初始化阶段:调用bean的初始化方法,执行自己的初始化逻辑,例如初始化数据库连接、读取配置文件等
- 使用阶段
- 销毁阶段:执行自己的销毁逻辑,例如关闭数据库连接、释放内存等等
- 终止阶段:容器调用bean的终止方法,确保bean不再使用或返回给容器,可能会执行一些清理任务、例如删除临时文件等等
- 回收阶段:容器将实例释放回给JVM,回收占用的内存资源。
依赖注入方法
-
构造方法注入
-
属性注入
-
工厂方法注入
- 非静态工厂方法
- 静态工厂方法
自动装配的方式
- byType
- byName
- constructor
- autodetect
Bean的作用域
- 单例
- Prototype:每次从容器中调用Bean,都会返回一个新的实例
循环依赖
当循环依赖的实例都采用setter方法注入的时候,可以支持,都采用构造器注入、不支持
bean初始化要经历三步:实例化、属性赋值、初始化;
三级缓存:
- 一级缓存:实例化、注入、初始化完成的bean实例
- 二级缓存:实例化完成的bean实例
- 三级缓存:bean创建工厂,以便后面有机会创建代理对象
解决方法:
- 先把实例化后的A放入三级缓存、但是不完整
- 注入属性发现缺少B,去实例化B
- 从一级缓存查到三级缓存,发现了A,把A放入二级缓存,B实例化、初始化完成,同时删除三级中的A
- A继续属性赋值、找到了B
Autowired实现原理
Bean的初始化阶段,会通过一些后置处理器来完成一些前置/后置的处理。
autowired就是通过后置处理器完成的,在创建bean的过程中,最终会调用doCreateBean()方法,在这个方法中会调用populateBean()方法、为bean进行属性填充、完成自动装配工作,这方法里调用了两次后置处理器,第二次就会进行对应的注解解析,实现自动装配。
SpringBoot启动原理
- 推断应用类型是普通项目还是web项目
- 查找并加载所有可用的初始化器,设置到initializers属性中
- 找出所有的应用程序监听器,设置到listeners属性中
- 推断并设置main方法的定义类,找到运行的主类
interrupt原理
Thread.interrupt() 向目标线程发送中断信号(即将目标线程的中断状态设置为 true,仅此而已)。Thread.interrupt() 方法并不能直接终止目标线程的执行。它只是改变了目标线程的中断状态,需要目标线程自行检查中断状态并作出相应的响应(一个线程不应该由其他线程强行终止)。
类加载过程
类加载的过程包括以下五个阶段:
- 加载。从文件系统、网络或其他来源获取类的二进制字节流。这个字节流被转换成方法区的运行时数据结构。在内存中,还会生成一个代表该类的java.lang.Class对象,这个对象作为方法区中该类的数据访问入口。
- 验证。确保Class文件中的字节流信息符合《Java虚拟机规范》的所有约束要求。这包括文件格式验证、元数据验证、字节码验证和符号引用验证。验证阶段确保类的方法体在逻辑上是正确的,没有安全漏洞。
- 准备。为类的静态变量分配内存并设置它们的初始值。这些初始值通常是被设为对应数据类型的零,但如果是final类型的静态变量,则它们的值会被直接复制为定义的值。
- 解析。虚拟机将常量池中的符号引用替换为直接引用的过程。符号引用可以是任何格式的字面量,无歧义即可。直接引用则可以直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
- 初始化。Java虚拟机开始执行类中编写的Java程序代码,将主导权移交给应用程序。在这个阶段,所有的静态变量会被赋值,静态初始化模块会被执行。
这些阶段共同完成了一个Java类的加载过程,确保了类在运行时能够被正确地加载和执行。
对象创建过程
在 JVM 中对象的创建,从一个 new 指令开始:
- 首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用
- 检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,就先执行相应的类加载过程
- 类加载检查通过后,虚拟机将为新生对象分配内存。
- 内存分配完成之后,虚拟机将分配到的内存空间(但不包括对象头)都初始化为零值。
- 接下来设置对象头,请求头里包含了对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息。
类加载器
- 启动类
- 扩展类
- 应用程序类
- 自定义类
双亲委派
编译期的优化和运行期的优化
内存间交互
堆外内存创建与回收
DirectByteBuffer 这个类是 JDK 提供使用堆外内存的一种途径,框架(如 Netty、RPC 等)可能会涉及,堆外内存优势主要体现在 IO 操作上,对于网络 IO,使用 Socket 发送数据时,能够节省java堆内存到堆外内存的数据拷贝,所以性能更高。Netty 使用堆外内存来实现零拷贝技术。对于磁盘 IO 时,也可以使用内存映射,来提升性能。另外,更重要的几乎不用考虑堆内存GC 问题。
首先向 Bits 类申请额度,Bits 类内部维护着当前已经使用的堆外内存值,会 check 当前申请的大小与实际已经使用的内存大小是否超过总的堆外内存大小
Cleaner 类,内部维护了一个 Cleaner 对象的链表,通过 create(Object, Runnable) 方法创建 cleaner 对象,调用自身的 add 方法,将其加入到链表中。更重要的是提供了 clean 方法,clean 方法首先将对象自身从链表中删除,保证只调用一次,然后执行 this.thunk 的 run 方法,thunk 就是由创建时传入的 Runnable 参数,也就是说 clean 只负责触发 Runnable 的 run 方法,至于 Runnable 做什么任务它不关心。
Filter,Interceptor
filter是java在servlet类中定义的,interceptor是spring框架中定义的 spring框架相关的项目,优先使用拦截器,所有filter能做的,interceptor都能做 使用范围不同:拦截器不仅可以用于Web程序,filter是servlet规范定义的,拦截器是在spring容器内的 filter不能使用spring容器资源,interceptor能使用spring中的任意资源、对象 filter是被server调用,interceptor是被spring调用,filter总是优先于interceptor调用 filter是基于函数回调,interceptor基于Java反射 filter是在servlet前后处理
- 设计原则:
- 李氏替换:子类替换父类,不能修改原有功能
- 单一职责:
- 开闭原则:对扩展开放,对修改封闭
- 接口隔离:接口设计尽量精简
- 依赖倒置:高层模块不应该依赖低层
- 访问修饰符
- private:同一个类中
- default:同一个类,同一个包
- protected:子类
- public:所有
- 抽象类和接口
- 接口:public方法,不能有实现;变量static final;
- 成员变量和局部变量
- string, integer转换
- Integer.valueOf(String a)
- String.valueOf()
- 反射:Java 程序的执行分为编译和运行两步,编译之后会生成字节码(.class)文件,JVM 进行类加载的时候,会加载字节码文件,将类型相关的所有信息加载进方法区,反射就是去获取这些信息,然后进行各种操作。
- 泛型:泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
- 类型擦除:Java 在编译期间,所有的类型信息都会被擦掉。编译的时候静态地检查一下范型类型是否正确,运行时不检查。
- 注解:三种生命周期
- AOP,使用注解作为切点就是运行期注解的应用;比如 lombok,就是注解在编译期的运行。
- 动态代理:JDK,CGLIB
- ArrayList:先检查是否需要扩容,1.5倍扩容,新建数组然后拷贝
- CopyOnWriteArrayList
- HashMap:两倍扩容,初始容量16,0.75负载因子
- HashTable:synchronized
- ConcurrentHashMap:数组位置i为空,CAS写入。不为空,synchronized写入
- LinkedHashMap
- TreeMap:红黑树
- HashSet 32.**