文章目录
Spring的IoC理解
IOC,Inversion of Control,控制反转(也叫:依赖注入),指将对象的控制权转移给Spring框架,由 Spring 来负责控制对象的生命周期(比如创建、销毁)和对象间的依赖关系。
最直观的表达就是,以前创建对象的时机和主动权都是由自己把控的,如果在一个对象中使用另外的对象,就必须主动通过new指令去创建依赖对象
,使用完后还需要销毁(比如Connection等),对象始终会和其他接口或类耦合起来。而 IOC 则是由专门的容器来帮忙创建对象,将所有的类都在 Spring 容器中登记,当需要某个对象时,不再需要自己主动去 new 了,只需告诉 Spring 容器,然后 Spring 就会在系统运行到适当的时机,把你想要的对象主动给你
。也就是说,对于某个具体的对象而言,以前是由自己控制它所引用对象的生命周期,而在IOC中,所有的对象都被 Spring 控制,控制对象生命周期的不再是引用它的对象,而是Spring 容器,由 Spring 容器帮我们创建、查找及注入依赖对象,而引用对象只是被动的接受依赖对象,所以这叫控制反转。
依赖注入
如上所述的一个例子,其实就是指的是 将调用者内部依赖的对象通过IOC容器注入调用者的过程。底层原理就是:反射
Spring的AOP理解
面向切面编程实际上是针对于OOP模式的一种补充,拿下面的一张图来解释即可:
而面向切面,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect
),减少系统中的重复代码,降低了模块间的耦合度,提高系统的可维护性。可用于权限认证、日志、事务处理。
实现方式通过代理来实现。具体见:静态代理与动态代理
spring 总览
BeanFactory 和 ApplicationContext 的区别?
https://zhuanlan.zhihu.com/p/115029344
BeanPostProcessor 和 BeanFactoryPostProcessor 的区别
BeanPostProcessor 具体实现:
BeanFactoryPostProcessor 具体实现:
总结区别
ApplicationContext 的实现
- FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。
- ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。
- WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。
bean的生命周期
主要关键步骤
实例化 Instantiation --> 属性赋值 Populate --> 初始化 Initialization --> 销毁 Destruction
Spring 容器的启动流程?
- 初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中
① 实例化BeanFactory【DefaultListableBeanFactory】工厂,用于生成Bean对象
② 实例化BeanDefinitionReader注解配置读取器,用于对特定注解(如@Service、@Repository)的类进行读取转化成 BeanDefinition 对象,(BeanDefinition 是 Spring 中极其重要的一个概念,它存储了 bean 对象的所有特征信息,如是否单例,是否懒加载,factoryBeanName 等)
③ 实例化ClassPathBeanDefinitionScanner路径扫描器,用于对指定的包目录进行扫描查找 bean 对象
- 将配置类的BeanDefinition注册到容器中
- 调用 refresh() 方法刷新容器:
① prepareRefresh()刷新前的预处理:
② obtainFreshBeanFactory():获取在容器初始化时创建的BeanFactory:
③ prepareBeanFactory(beanFactory):BeanFactory的预处理工作,向容器中添加一些组件:
④ postProcessBeanFactory(beanFactory):子类重写该方法,可以实现在BeanFactory创建并预处理完成以后做进一步的设置
⑤invokeBeanFactoryPostProcessors(beanFactory)
:在BeanFactory标准初始化之后执行BeanFactoryPostProcessor的方法,即BeanFactory的后置处理器
:
⑥registerBeanPostProcessors(beanFactory)
:向容器中注册Bean的后置处理器BeanPostProcessor,它的主要作用是干预Spring初始化bean的流程,从而完成代理、自动注入、循环依赖等功能
⑦ initMessageSource():初始化MessageSource组件,主要用于做国际化功能,消息绑定与消息解析:
⑧ initApplicationEventMulticaster():初始化事件派发器,在注册监听器时会用到:
⑨ onRefresh():留给子容器、子类重写这个方法,在容器刷新的时候可以自定义逻辑
⑩ registerListeners():注册监听器:将容器中所有的ApplicationListener注册到事件派发器中,并派发之前步骤产生的事件:
⑪ finishBeanFactoryInitialization(beanFactory):初始化所有剩下的单实例bean,核心方法是preInstantiateSingletons(),会调用getBean()方法创建对象;
⑫ finishRefresh():发布 BeanFactory 容器刷新完成事件
如何解决循环依赖问题?
@Lazy 注解
与写时复制类似,主要解决构造方法造成的循环依赖问题
三级缓存
对于对象之间的普通引用,二级缓存会保存 new 出来的不完整对象,这样当单例池中找到不依赖的属性时,就可以先从二级缓存中获取到不完整对象,完成对象创建,在后续的依赖注入过程中,将单例池中对象的引用关系调整完成
。
三级缓存:如果引用的对象配置了AOP,那在单例池中最终就会需要注入动态代理对象,而不是原对象。而生成动态代理是要在对象初始化完成之后才开始的
。于是Spring增加三级缓存, 保存所有对象的动态代理配置信息。在发现有循环依赖时,将这个对象的动态代理信息获取出来,提前进行AOP,生成动态代理。
核心代码就在 DefaultSingletonBeanRegistry 的 getSingleton 方法当中。
Spring 中什么时候 @Transactional 会失效?(有6种)
- 加了@Transactional 的方法只有是被代理对象调用时,那么这个注解才会生效,所以如果是原型对象来调用这个方法,那么@Transactional是不会失效的。举例:
开发中避免不了会对同一个类里面的方法调用,比如有一个类Test,它的一个方法A,A再调用本类的方法B(不论方法B是用public还是private修饰),但方法A没有声明注解事务,而B方法有。则外部调用方法A之后,方法B的事务是不会起作用的。这也是经常犯错误的一个地方
- 同时
如果某个方法是 private 的,那么@Transactional也会失效
, 因为底层 cglib 是基于父子类来实现的,子类是不能重载父类的private方法的,所以无法很好的利用代理,也会导致@Transactianal失效 - 设置了相应的事务传播机制
- rollbackFor 设置错误,Spring默认抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error才回滚事务;
- 异常被你的 catch“吃了”导致@Transactional 失效,如果是编译时异常不会自动回滚,如果是运行时异常,就会自动回滚!
- 数据库引擎不支持事务