「AOP 实现主要分为两类:」
-
「静态 AOP 实现」, AOP 框架 「在编译阶段」 对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ
-
「动态 AOP 实现」, AOP 框架 「在运行阶段」 对动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP
spring 中 AOP 的实现是 「通过动态代理实现的」 ,如果是实现了接口就会使用 JDK 动态代理,否则就使用 CGLIB 代理。
「有 5 种通知类型:」
-
「@Before」:在目标方法调用前去通知
-
「@AfterReturning」:在目标方法返回或异常后调用
-
「@AfterThrowing」:在目标方法返回后调用
-
「@After」:在目标方法异常后调用
-
「@Around」:将目标方法封装起来,自己确定调用时机
9.动态代理和静态代理有什么区别?
=================
「静态代理」
-
由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了
-
静态代理通常只代理一个类
-
静态代理事先知道要代理的是什么
「动态代理」
-
在程序运行时,运用反射机制动态创建而成
-
动态代理是代理一个接口下的多个实现类
-
动态代理不知道要代理什么东西,只有在运行时才知道
10.JDK 动态代理和 CGLIB 代理有什么区别?
===========================
JDK 动态代理时业务类 「必须要实现某个接口」 ,它是 「基于反射的机制实现的」 ,生成一个实现同样接口的一个代理类,然后通过重写方法的方式,实现对代码的增强。
CGLIB 动态代理是使用字节码处理框架 ASM,其原理是通过字节码技术为一个类 「创建子类,然后重写父类的方法」 ,实现对代码的增强。
11.Spring AOP 和 AspectJ AOP 有什么区别?
==================================
Spring AOP 是运行时增强,是通过 「动态代理实现」 的
AspectJ AOP 是编译时增强,需要特殊的编译器才可以完成,是通过 **「修改代码来实现」**的,支持 「三种织入方式」
-
「编译时织入」:就是在编译字节码的时候织入相关代理类
-
「编译后织入」:编译完初始类后发现需要 AOP 增强,然后织入相关代码
-
「类加载时织入」:指在加载器加载类的时候织入
主要区别 | Spring AOP | AspecjtJ AOP |
增强方式 | 运行时增强 | 编译时增强 |
实现方式 | 动态代理 | 修改代码 |
编译器 | javac | 特殊的编译器 ajc |
效率 | 较低(运行时反射损耗性能) | 较高 |
织入方式 | 运行时 | 编译时、编译后、类加载时 |
12.Spring 中 Bean 的生命周期是怎样的?
===========================
SpringBean 生命周期大致分为4个阶段:
-
1. 「实例化」 ,实例化该 Bean 对象
-
2. 「填充属性」 ,给该 Bean 赋值
-
3. 「初始化」
-
如果实现了 Aware 接口,会通过其接口获取容器资源
-
如果实现了 BeanPostProcessor 接口,则会回调该接口的前置和后置处理增强
-
如果配置了 init-method 方法,]会执行该方法
-
4. 「销毁」
-
如果实现了 DisposableBean 接口,则会回调该接口的 destroy 方法
-
如果配置了 destroy-method 方法,则会执行 destroy-method 配置的方法
13.Spring 是怎么解决循环依赖的?
=====================
循环依赖就是说两个对象相互依赖,形成了一个环形的调用链路
spring 使用三级缓存去解决循环依赖的,其 「核心逻辑就是把实例化和初始化的步骤分开,然后放入缓存中」 ,供另一个对象调用
-
「第一级缓存」:用来保存实例化、初始化都完成的对象
-
「第二级缓存」:用来保存实例化完成,但是未初始化完成的对象
-
「第三级缓存」:用来保存一个对象工厂,提供一个匿名内部类,用于创建二级缓存中的对象
当 A、B 两个类发生循环引用时 大致流程
-
1.A 完成实例化后,去 「创建一个对象工厂,并放入三级缓存」 当中
-
如果 A 被 AOP 代理,那么通过这个工厂获取到的就是 A 代理后的对象
-
如果 A 没有被 AOP 代理,那么这个工厂获取到的就是 A 实例化的对象
-
2.A 进行属性注入时,去 「创建 B」
-
3.B 进行属性注入,需要 A ,则 「从三级缓存中去取 A 工厂代理对象」 并注入,然后删除三级缓存中的 A 工厂,将 A 对象放入二级缓存
-
4.B 完成后续属性注入,直到初始化结束,将 B 放入一级缓存
-
5. 「A 从一级缓存中取到 B 并且注入 B」 , 直到完成后续操作,将 A 从二级缓存删除并且放入一级缓存,循环依赖结束
spring 解决循环依赖有两个前提条件:
-
1. 「不全是构造器方式」 的循环依赖(否则无法分离初始化和实例化的操作)
-
2. 「必须是单例」 (否则无法保证是同一对象)
14.为什么要使用三级缓存,二级缓存不能解决吗?
========================
可以,三级缓存的功能是只有真正发生循环依赖的时候,才去提前生成代理对象,否则只会 「创建一个工厂并将其放入到三级缓存」 中,但是不会去通过这个工厂去真正创建对象。
如果使用二级缓存解决循环依赖,意味着所有 Bean 在实例化后就要完成 AOP 代理,这样 「违背了 Spring 设计的原则」 ,Spring 在设计之初就是在 Bean 生命周期的最后一步来完成 AOP 代理,而不是在实例化后就立马进行 AOP 代理。
15.@Autowired 和 @Resource 有什么区别?
================================
-
「@Resource 是 Java 自己的注解」,@Resource 有两个属性是比较重要的,分是 name 和 type;Spring 将 @Resource 注解的 name 属性解析为 bean 的名字,而 type 属性则解析为 bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。
-
「@Autowired 是spring 的注解」,是 spring2.5 版本引入的,Autowired 只根据 type 进行注入, 「不会去匹配 name」 。如果涉及到 type 无法辨别注入对象时,那需要依赖 @Qualifier 或 @Primary 注解一起来修饰。
16.Spring 事务隔离级别有哪些?
====================
-
DEFAULT:采用 DB 默认的事务隔离级别
-
READ_UNCOMMITTED:读未提交
-
READ_COMMITTED:读已提交
-
REPEATABLE_READ:可重复读
-
SERIALIZABLE:串行化
17.Spring 事务的传播机制有哪些?
=====================
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-tOguyELu-1710866984229)]
[外链图片转存中…(img-yke4EPqS-1710866984230)]
[外链图片转存中…(img-6FlMhG2G-1710866984230)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-KkkZD9V7-1710866984231)]