@Autowired 和@Resource 的区别
@Autowired只适用于spring框架,而@Resource 是java官方注解,其他框架也能用
自动匹配顺序不同,@Autowired先按类型找且必须加@Qualifier,而@Resource先按名称找,名称匹配不到再按类型匹配,且无需额外属性
那为什么官方更推荐构造器注入呢
构造器的优点:强制不可变,杜绝空指针/便于单元测试/遵循单一职责/提前暴露循环依赖
实际用的少的原因:CRUD业务无感知,写法繁琐,开发便捷性差
Spring AOP
面向切面编程,用于将与业务无关的横切关注点如日志,事务,安全,权限等抽取出来,封装成切面。通过在不修改原有代码的情况下将通用功能动态织入多个方法执行的特定位置,实现代码解耦和复用
AOP是怎么实现的?动态代理和静态代理有何区别
AOP主要是通过代理机制实现的。动态代理是指运行时由JVM生成代理类如:JDK动态代理或GGLIB(默认使用),适用于Spring AOP;静态代理则在编译时或类加载期由工具修改字节码完成织入
AOP有哪些主要组成部分?
AOP的主要组成部分包括:切面(Aspect)、连接点(Join Point)、通知(Advice)、切入点(Pointcut)和织入(Weaving)。切面封装横切逻辑;连接点是程序执行的特定位置;通知是切面在连接点执行的动作;切入点定义匹配哪些连接点;织入是将切面应用到目标对象的过程。
Spring AOP和AspectJ有什么区别?
Spring AOP是基于动态代理的轻量级实现,仅支持方法级别的织入,使用简单,集成方便;AspectJ是功能更强大的AOP框架,支持字段、构造器、初始化等多粒度织入,可在编译期织入,性能更好,但配置复杂,需要专用编译器或织入器
Spring事务
Spring支持事务的方式主要有两种:编程式事务和声明式事务,前者很少使用,后者实际上是通过AOP实现的,基于@Transactional的全注解使用最多
Spring事务会在什么情况下失效
spring的事务主要靠AOP代理的,凡是绕过代理或代理机制本身搞不定的情况,事务就会失效
- 多线程环境,因为@Transactional是基于ThreadLocal存储上下文的,在多线程情况下每个线程都有自己的上下文,所以无法保持事务同步
- try catch捕获异常了,但没有抛出,因此事务以为没报错,正常提交,不会回滚
- 同一个类里面方法调用,因为事务是基于动态调用实现的,同类的方法调用不会走代理
- @Transactional应用在final和static方法上
- @Transactional应用在非public修饰的方法上
- propagation 传播机制配置错误,可能是新起事务了
- rollbackFor没设置,Spring事务默认只回滚运行时异常(RuntimeException)和系统异常(Error),而抛出受检异常比如IOException,它不回滚,必须手动rollbackFor=Exception.class才会全部回滚
为什么Spring循环依赖需要三级缓存,二级不够吗
二级缓存能够解决循环依赖问题,三级则是通过存储一个工厂实现延迟加载,只有真正发生循环依赖的时候才触发代理创建,没有循环依赖则这个工厂不会被调用,相当于是提前暴露,提前判断,延迟加载
所以引入了三级不是为了解决循环依赖,而是在解决的同时兼容AOP代理
三级缓存中存放的是什么?它的作用是什么?
一个能够创建早期Bean引用的工厂对象。当Bean实例化完成之后,先把这个工厂放到三级缓存,而不立即产生代理,是根据后续是否出现循环依赖来触发工厂,这时候工厂才会把这个Bean代理的对象给别的用
如果只用二级缓存解决循环依赖会有什么问题
如果仅使用二级,那么会导致所有涉及AOP的Bean都在生命周期早期就被代理,打破了Spring规定的必须在初始后创建的流程
SpringBean的生命周期
生命周期大致分为:实例化->属性赋值->初始化->就绪->销毁。
扩展点在Aware接口回调(在属性赋值后),以及在初始化前后的BeanPostProcessor
实现Aware接口,Bean就能在生命周期早期获取名字,工厂,容器上下文
BeanPostProcessor前置处理可修改Bean,而后置处理使得AOP代理在此生成,替换了原Bean
Bean的初始化方法有哪些?
可以 使用@PostConstruct注解,或者通过initialzingBean接口重写afterProspretisSest()方法
也可以在@Bean注解中指定initMethod属性来定义初始方法,三者可以同时存在,按此顺序依次执行