SpringIOC
Spring事务
SpringMVC
感觉MVC随便看看就行,最主要的还是那张大图要记住。
@Configuration
public class AppConfig { @Beanpublic TransferService transferService() {return new TransferServiceImpl(); }
}@Component
public class ServiceImpl implements AService { ....
}@Bean
public OneService getService(status) {case (status) {when 1:return new serviceImpl1();when 2:return new serviceImpl2();when 3:return new serviceImpl3(); }
}
@Configuration
public class AppConfig {@Beanpublic MyBean myBean() {// instantiate, configure and return bean ... }
}
整体流程(除去各种PostProcessor的细节) :
能够进行AOP切片的位置
在上述的图中,从BeanDefinitionReader得到的BeanDefinition还是会有占位符,不会替换。在invokeBeanFactoryPostProcessor中会将占位符,替换成我们配置信息。
在实例化对象前(3.5步骤),会准备beanPostProcesspr,准备监听器,事件和广播器。(观察者模式)
如果要自己debug,从preInstantiateSingletons()方法开始debug。
Bean对象成为成品的流程是:
一级缓存是singletonObjects,用于存放完成实例化和初始化的bean对象。(成品)
二级缓存是earlySingletonObjects,用于存放完成实例化但未完成初始化的bean对象。(经过AOP增强过半成品)
三级缓存是singletonFactories,用于存放需要进行AOP增强,但还未进行增强的半成品。(未经过AOP增强的半成品)
三级缓存的流程:
如果没有循环依赖的话,直接在将属性填充以后,直接调用三级缓存,进行AOP增强,放到一级缓存,不会使用二级缓存。
不行,如果仅仅使用一级缓存,会导致半成品对象和成品对象放到了一个map中,会导致后面取出的对象是半成品对象。
在不使用aop增强的情况下是可以的,但是在使用aop增强后,因为aop也是输入一个对象,然后生成了一个对象,也需要两个缓存池子去存,因此也是不可以的。
三级缓存主要解决了aop过程中产生的循环依赖的问题,aop需要一个原对象,然后生成一个代理对象。三级缓存中缓存的是原对象,二级缓存中缓存的是经过aop代理后生成的代理对象。如果没有三级缓存,则会导致代理对象和原对象都存储到二级缓存中,依旧会导致取出的对象不是成品对象的问题。
- IOC是一种控制反转的思想,原来的对象是由使用者来创建的,Spring是由把整个对象交给Spring来管理的。其实实现方式DI依赖注入,比如方法populateBean()来完成对实例后的对象的属性进行填充。
- IOC是一种容器,是通过三级缓存的方式在存储的,一般完整的bean对象是存储在singletonObjects的ConcurrentHashMap中。
- 首先Spring在开始时创建BeanFactory,并像BeanFactory中设置一些属性,包括==BeanPostProcessor,和Aware接口的子类等。
- 从XML等方式加载配置文件信息到BeanDefinition中。
- 然后触发BeanFactoryPostProcessor增强器,进行相应的处理,这里可以做很多扩展处理,例如在这里会对配置文件中的占位符进行置换。
- 注册BeanPostProcessor,方便对后面创建的对象进行拓展。
- BeanFactory会通过反射的方式,将Bean对象实例化,目前这个对象没有属性被填充。
- 然后就开始了一个bean的生命周期,包括填充bean对象的属性,调用aware子类的方法,一般顺序是先beanNameAware,然后是BeanFactoryAware,然后是ApplicationContextAware,然后调用BeanPostProcessor的前增强器,然后调用init_method方法,然后调用BeanPostProcessor的后增强器。
- 然后生成了一个完整的bean,通过getBean的方法可以获取这个bean
- 最后销毁Bean
这是我对SpringIOC的理解,面试官您有什么疑问?
- bean的创建过程分为实例化和初始化两个部分
1. 先创建A对象,实例化A对象,此时A对象的B属性为空
2. 对A对象的属性进行注入,但是没有找到B对象,因此去创建B对象
3. 实例化B对象,此时B对象的A属性为空
4. 填充B对象的A属性时,依旧找不到A对象,尝试去创建A对象,由此导致的循环创建对象的过程。
- 解决循环依赖问题的关键点在于A对象虽然没有创建完成,但是已经被实例化了的半成品。我们已经拥有了该对象的引用,可以在后续的操作中给他赋值,相当于提前暴露了A对象的引用,解决循环依赖的关键是实例化和初始化分开操作。因此对于构造函数初始化的循环引用是无法避免的
- 当所有的对象都完成实例化和初始化操作后,容器中的对象会有两种状态,已经实例化但是未完成初始化的状态,和完全初始化状态。因此使用了两种不同的容器进行存储,就是一级缓存和二级缓存。如果一级缓存有了,就不会在二级缓存中出现,三级缓存的查询顺序是一级、二级和三级。一级缓存中存储的是完整对象,二级缓存存储的是非完整对象。
- 三级缓存中value存储的ObjectFactory,存储的是lambda表达式,三级缓存主要解决的是如果这个过程存在aop操作,则会需要一个普通对象,然后通过代理生成新的代理对象。在IOC容器中是不允许同时出现两个相同的对象的,当一个对象需要被代理的时候,需要使用代理对象覆盖掉原来的对象。
- 在实际调用的过程中,是没有办法判断对象什么时候被调用,所以当某个对象被调用时,有先判断这个对象是否需要被代理,类似于一种回调机制。因此当传入lambda表达式式,可以通过lambda来执行代理对象覆盖原对象的操作。
三级缓存: createBeanInstance之后: addSingletonFactory
二级缓存:第一次从三级缓存确定对象是代理对象还是普通对象的时候,同时删除三级缓存getSingleton
-级缓存:生成完整对象之后放到一级缓存,删除二三级缓存:addSingletonFactory
SpringAOP的功能有哪些:事务,权限验证,异常处理,log记录
Aspect:切面 = join point + pointcut + advice;
joinpoint:连接点,需要被增强的每一个方法
pointcut:切点,一堆连接点的集合,指出需要被增强的范围。
advice:通知,包括增强逻辑和增强位置(Before,AfterReturning ,AfterThrowing,Around)。
weaving:织入,实现增强的过程(静态增强,动态增强)
TargetObject:需要被代理的对象
proxy:代理以后生成的代理对象
下图所示
@Aspect 表示这是一个切面,切面也是一个bean,因此用@component装填到IOC容器中。
@advice表示的方法内部表示的是增强逻辑,@before和@After表示的是增强时机。
@pointcut表示要增强的范围,execution(~)的内容
在(~)中的每一个方法就是joincut。
代码可以插入的位置,(advice能够插入的位置):
当有多个通知时,需要有一套责任链来排序advice执行的顺序。
Spring中每一个advice都要实现MethodInterceptor接口,CGLIB动态代理中CallBack()接口需要传入的内容。
public interface PlatformTransactionManager {TransactionStatus getTransaction(@Nullable TransactionDefinition definition);void commit(TransactionStatus status) throws TransactionException;void rollback(TransactionStatus status) throws TransactionException;
}
总:
Spring事务是通过AOP的形式来实现的。Spring事务对AOP的事务通知进行了定制化,没有使用Aop的Advice,而是自己实现了MethodInterceptor,并调用invoke方法。
分:
首先实例化并初始化一个bean对象,获得事务相关的切点,切面,连接点等。
如果需要开启事务则,需要连接数据库,开启事务。
如果事务执行失败,会会通过completeTransactionAfterThrowing,调用doRollback()方法,具体也是通过数据库连接来实现数据库的回滚操作。
如果事务执行成功,会会通过completeTransactionAfterReturning,调用doCommit()方法,具体也是通过数据库连接来实现数据库的提交操作。
最后执行完毕后,清除相关事务信息,调用clearupTransactionInfo()清除事务信息。
@SpringBootApplication
,这个注解表明了这个类是Spring Boot的启动类,其中的@EnableAutoConfigration
是实现自动装配的核心注解,其中的使用@import引入了AutoConfigurationImportSelector
类,这个类是Spring Boot实现自动装配核心。AutoConfigurationImportSelector
中继承了selectImports()方法,这个方法用于获取所有符合条件的全限定类名
,并加载到IOC容器中。getAutoConfigurationEntry()
方法,先把所有的META-INF/SpringFactories中以AutoConfigration为后缀的配置文件全部加载进来,然后根据@CondiOn
注解来判断是否将该配置文件注入IOC容器中。