Spring框架部分知识
Spring单例bean是否线程安全?
线程安全的定义:在多线程环境中,一个类或代码段能够被多个线程安全地访问,而不会出现数据竞争、状态不一致或其他意外行为。
单例bean无法保证线程安全,他可能会产生线程安全问题,所以单例bean不是线程安全的。
但是不是线程安全的,在使用过程中并不一定就会产生线程安全问题,就算是线程不安全的,在合理的使用下也能够不对数据造成危害。比如:虽然bean是线程不安全的,但是它的成员变量如果都是无状态(不做修改)的,就算使用单例bean,也不会对数据产生影响。
重点应该是将线程是否安全的和是否一定会产生线程安全问题区分,线程不安全的也可以以不产生线程安全问题的方式实现。
补充了解:
当不同请求同时访问单例时,spring容器中只有一个单例,spring容器接收不同请求,并为这些请求创建不同线程并发访问spring容器中的单例对象。
AOP底层原理?
什么是AOP?
面向切面编程,用来 抽取与业务无关但对多个对象产生影响的公共代码,实现了代码复用和解耦。常见场景:记录日志,事务处理。
使用流程?
构建一个切面类,在切面类中实现增强方法,在增强方法上使用注解指定执行时间和执行地点(在哪个方法的什么时候执行)。
动态代理。
Cglib:通过jar包产生新的class文件,对新的class文件进行实例化,即实例化了一个新的代理对象。通过责任链来执行增强方法。
而jdkProxy中,将bean对象作为一个成员变量来生成代理对象。通过责任链来执行增强方法。
项目启动时,会创建IOC容器,并将IOC容器内的bean进行构造,填充属性,初始化,在bean生命周期中的初始化结束后,spring会调用所有BeanPostProcessor的postProcessAfterInitialization
方法,Spring会检查该Bean是否需要被代理(通过获取所有的增强advice和判断当前bean是否满足配置的切面条件),满足条件则构造代理对象。
为了同一,方便的构造代理对象,应用了工厂设计模式,有一个专门生产代理对象的工厂proxyFactory,在该工厂中制定了具体生产对象的方式。
生产对象的两种方式:
Cglib:
使用enhencer来设置i基本信息及生成增强的调用链,基于ASM生成新的class文件,实例化它的对象,调用bean方法时会执行intercept方法,与invoke方法类似。
jdkProxy:
创建一个实现了目标对象实现接口的代理对象,并将目标对象作为它的成员变量,通过成员变量来执行目标对象上的相应方法,调用bean方法时,或执行invoke方法,通过execution表达式获取所有与该方法(bean方法)匹配的增强方法,并使用责任链模式,将它们排序,生成调用链,按顺序执行调用链,中间穿插执行bean方法。
Cglib和jdkProxy区别:
1.使用JDKProxy必须保证目标对象实现接口,而使用Cglib必须保证目标对象不使用final。
2.动态代理使用的是在运行时生成的class文件,
JDKProxy由JDK生成,而Cglib会使用第三方的ASM生成,
JDK生成的代理类会实现目标对象的类接口,所以目标对象必须实现接口,
Cglib中ASM生成的类会继承目标对象的类,所以目标对象不能使用final关键字,
3.JDKProxy使用反射调用目标对象执行方法,
Cglib直接使用子类调用目标对象执行方法。
Spring事务的底层实现?
Spring事务底层使用AOP实现,
1.解析切面,在bean被构造,数据填充,初始化后,执行beanPostProcessor时进行解析advicer,这个advicer是由于使用注解@EnableTransactionManagement导入了一个配置类,这个配置类配置了advicer,该advicer的切入点通过事务注解声明,在advicer中配置了事务的增强方法。
2.生成代理对象。
3.调用。
使用try catch,在执行方法前创建一个数据库连接,禁用数据库自动提交,执行方法,如果抛出异常需要回滚则回滚,否则仍然提交。如果未出现异常直接提交。
建议结合参见:
1.【史上最完整的AOP底层原理】https://www.bilibili.com/video/BV1SY41117zqvd_source=a70a5573b182a2efadab0e4922233ceb
2.【腾讯二面:Spring AOP底层实现原理是怎么样的?JDK和CGlib动态代理有什么区别 ?】https://www.bilibili.com/video/BV1MJ4m1Y784vd_source=a70a5573b182a2efadab0e4922233ceb
Spring中bean对象的生命周期?
1.获取bean配置
2.实例化bean对象
3.依赖注入,属性赋值
4.实现了aware接口,执行对应方法
5.执行BeanPostProcessor的前置处理器
6.执行初始化方法
7.执行BeanPostProcessor的后置处理器
8.销毁bean对象