目录
1.1、注解@Autowired和@Resource有什么区别?
1.2、 BeanFactory和ApplicationContext有什么区别?
如果一个对象需要被代理,或者说需要生成代理对象,那么要不要优先生成一个普通对象?
(2)Pointcut: 切入点(具体项目中真正已经被增强的方法:方法上添加@Pointcut注解,配置切入点)
(2)Aspect: 切面(存放通知的类:@Aspect指定哪个类是切面)
(3)Advice: 通知/增强 (具体用于增强方法的代码)
3.1 注解方式配置声明式事务(@Transcation):
3.3 Spring的事务是如何回滚的?spring的事务管理是如何实现的?
一、谈谈Spring IOC得理解,原理与实现
总:
控制反转:它只是理论思想,原来的对象是我们创建的;有了spring之后,可以把整个对象交给spring来帮我们进行管理,这样就可以解耦。
它的具体实现是DI:依赖注入,把对应的属性的值注入到具体的对象中,@Autowired,@Resource,populateBean方法来完成属性值的注入(赋值)。
容器:存储对象,使用map结构来存储,通过BeanFactory和ApplicationContext两个接口来创建Bean。整个bean的生命周期,从创建到使用到销毁的过程全部都是由容器来管理的(bean的生命周期) spring中的bean都是通过反射的方式生成的(constructor,newinstance),ioc中最核心的也就是填充具体bean的属性(初始化)
在spring中一般存在三级缓存,singletonObjects存放完整的bean对象,earlysingletonObjects存放半成品对象,singletonFactory用来存放Lambda表达式和对象名称的映射。
1.1、注解@Autowired和@Resource有什么区别?
- @Autowird默认的注入方式为byType,也就是根据类型匹配。当有多个实现时,则通过byName注入,也可以通过配合@Qualifier注解来显式指定name值,指明要使用哪个具体的实现类
- @Resource默认通过byName注入,如果没有匹配则通过byType注入。同时@Resource还有两个重要的属性:name和type,用来显式指定byName和byType方式注入。
1.2、 BeanFactory和ApplicationContext有什么区别?
- BeanFactory是访问spring容器的根接口,提供基本的IOC和DI功能。
- 而ApplicationContext实现了该接口,对该接口做了一些扩展,提供了更多的api的调用。所以一般情况下使用ApplicationContext更多。
1.3、描述一下bean的生命周期
spring容器帮助我们去管理对象,从对象的产生到销毁都是由容器来控制的,其中主要是实例化和初始化的过程:
- 实例化Bean,通过反射的方式生成对象,有一个createBeanInstance是专门用来生成对象的。
- bean对象创建完,它的属性值都是默认值,所以需要填充bean的属性:通过populateBean()来填充属性,会存在循环依赖的问题(三级缓存)
- 向bean对象中设置容器属性:invokeAwareMethods方法来将容器对象设置到具体的bean对象中。
- 调用BeanPostProcessor中的前置处理方法:使用比较多的有(ApplicationContextPostProcessor设置ApplicationContext,Environment,ResourceLoader,EmbeddValueResolver等对象)
- 调用invokeInitmethods方法来完成初始化方法的调用,判断是否实现了InitializingBean接口,如果有,调用afterPropertiesSet方法,
- 调用BeanPostProcessor的后置处理方法,Bean初始化完成:spring的aop就是在此处实现的,实现接口名字AbstractAutoProxyCreator
- 通过getBean的方式来进行对象的获取
- 对象使用完毕,容器关闭对象就会销毁 ①判断是否实现了DispoableBean接口②调用destroyMethod方法
1.4 谈一下spring IOC的底层实现
底层实现:工作原理,过程,数据结构,流程,设计模式,设计思想
你对他的理解和你了解过的实现过程
反射,工厂,设计模式,关键的几个方法
createBeanFactory , getBean ,doGetBean , createBean , doCreateBean,createBeanInstance(getDeclaredConstructor(),newinstance),populateBean
- 先通过createBeanFactory 创建一个Bean工厂(DefaultListableBeanFactory)
- 开始循环创建对象,因为容器中的bean默认都是单例的,所以优先通过getBean,doGetBean从容器中查找,找不到的话,
- 通过createBean,doCreateBean方法,以反射的方式创建对象,一般情况下使用的是无参的构造器(getDeclaredConstructor(),newinstance)
- 进行对象的属性填充populateBean
- 进行其他的初始化操作(initializingBean)
1.5、Spring是如何解决循环依赖的问题的?
三级缓存,提前暴露对象,aop
总:什么是循环依赖问题,A依赖B,B依赖A
分:先说明bean得创建过程:实例化,初始化(填充属性)
- 先创建A对象,实例化A对象,此时A对象中的b属性为空
- 从容器中查找B对象,如果找到了,直接赋值不存在循环依赖问题(不通),找不到直接创建B对象
- 实例化B对象,此时B对象中的a属性为空,填充属性a
- 从容器中查找A对象,找不到,直接创建
此时,如果仔细琢磨的话,会发现A对象,是存在的,只不过此时的A对象不是一个完整的状态,只完成了实例化但是未完成初始化,如果在程序调用过程中,拥有了某个对象的引用,能否在后期给他完成赋值操作,可以优先把非完整状态的对象优先赋值,等待后续操作来完成赋值,相当于提前暴露了某个不完整对象的引用,所以解决问题的核心在于实例化和初始化分开操作,这也是解决循环依赖问题的关键,
当所有的对象都完成实例化和初始化操作之后,还要把完整对象放到容器中,此时在容器中存在对象的几种状态,完成实例化=但未完成初始化,完整状态,因为都在容器中,所以要使用不同的map结构来进行存储,此时就有了一级缓存和二级缓存,如果一级缓存中有了,那么二级缓存中就不会存在同名的对象,因为他们的查找顺序是1,2,3这样的方式来查找的。一级缓存中放的是完整对象,二级缓存中放的是非完整对象,
为什么需要三级缓存?
三级缓存的value类型是ObjectFactory,是一个函数式接口
存在的意义是保证在整个容器的运行过程中同名的bean对象只能有一个。
如果一个对象需要被代理,或者说需要生成代理对象,那么要不要优先生成一个普通对象?
要,普通对象和代理对象是不能同时出现在容器中的,因此当一个对象需要被代理的时候,就要使用代理对象覆盖掉之前的普通对象,在实际的调用过程中,是没有办法确定什么时候对象被使用,所以就要求某个对象被调用的时候,优先判断此对象是否需要被代理,类似于一种回调机制的实现,因此传入lambda表达式的时候,可以通过lambda表达式来执行对象的覆盖过程,getEarlyBeanReference()
因此,所有的bean对象在创建的时候要优先放到三级缓存中,在后续的使用过程中,如果需要被代理则返回代理对象,如果不需要被代理,则直接返回普通对象
1.6 Spring 中的 bean 的作用域有哪些?
- singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
- prototype : 每次请求都会创建一个新的 bean 实例。
- request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。 session : :在一个HTTP Session中,一个Bean定义对应一个实例。该作用域仅在基于web的 Spring ApplicationContext情形下有效。
- global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码(例如:HTML)片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是与 servlet 不同,每个 portlet 都有不同的会话
二、Spring的AOP的底层实现原理
AOP就是面向切面编程(在不修改源码的情况下,对已有方法进行增强)就是将程序中重复利用的代码抽取成一个工具类,在使用的时候用动态代理的方法进行增强。可用于权限认证、日志、事务处理等。
2.1使用动态代理
- JDK动态代理: JDK的proxy通过实现接口来实现扩展功能。
- Cglib动态代理: 它底层使用的是字节码的增强技术,可以生成目标类的一个子类。去实现一个代理的功能。但是它要求目标类必须能被继承,即不能是final类。
- Cglib在创建对象的过程中速度比较慢,但是在运行时效率更高一些。
(1)JoinPoint: 连接点(所有可以被增强的方法)
类里面哪些方法可以被增强,这些方法称为连接点. 在spring的AOP中,指的是业务层的类的所有现有的方法。
(2)Pointcut: 切入点(具体项目中真正已经被增强的方法:方法上添加@Pointcut注解,配置切入点)
在类里面可以有很多方法被增强,但是实际开发中,我们只对具体的某几个方法而已,那么这些实际增强的方法就称之为切入点
(2)Aspect: 切面(存放通知的类:@Aspect指定哪个类是切面)
(3)Advice: 通知/增强 (具体用于增强方法的代码)
比如给某个切入点(方法) 扩展了校验权限的功能,那么这个校验权限即可称之为增强或者是通知
- 前置通知(@Before注解): 在被增强的方法之前执行.
- 后置通知(@AfterReturning注解): 在被增强的方法之后执行. 特点: 可以得到被增强方法的返回值
- 异常通知(@AfterThrowing注解): 在被增强的方法执行出现异常的时候执行. 如果方法没有异常,不会执行. 特点:可以获得异常的信息
- 最终通知(@After注解): 指的是无论是否有异常,总是被执行的。
- 环绕通知(@Around注解):在方法之前和方法之后执行. 特点:可以阻止目标方法执行
三、Spring中的事务
3.1 注解方式配置声明式事务(@Transcation):
- 配置事务管理者
- 加载事务注解驱动
-
在代码中使用@Transactional注解来标注,哪个方法需要使用事务
3.2 @Transactional注解:
(1)rollbackFor 表示该事务遇到什么就回滚,默认是遇到所有的异常都回滚
(2)noRollbackFor 表示该事务遇到什么不回滚
(3)timeout 表示事务的超时时间,默认为-1
(4)readOnly 表示该事务是只读事务,所以配置了readOnly的事务属性的方法中不能进行数据库的增删改操作
(5) isolation 表示该事务的隔离级别:
- READ_UNCOMMITTED 读取到未提交的事务
- READ_COMMITTED 读取到已提交的事务
- REPEATABLE_READ 可重复读
- SERIALIZABLE 串行化
3.3 Spring的事务是如何回滚的?spring的事务管理是如何实现的?
总:spring的事务是由aop来实现的,首先要生成具体的代理对象,然后按照aop的整套流程来执行具体的操作逻辑,正常情况下要通过通知来完成核心功能,但是事务不是通过通知实现的,而是通过一个TransactionInterceptor来实现的,然后调用invoke来实现具体的逻辑。
分:
- 先做准备工作,解析各个方法上事务相关的属性,根据具体的属性来判断是否开始新事务
- 当需要开启的时候,获取数据库连接,关闭自动提交功能,开启事务
- 执行具体的sql逻辑操作
- 在操作过程中,如果执行失败了,那么会通过completeTransactionAfterThrowing看来完成事务的回滚操作,回滚的具体逻辑是通过doRollBack方法来实现的,实现的时候也是要先获取链接对象,通过连接对象来回滚。
- 如果执行过程中,没有任何意外情况的发生,那么通过commitTransactionAfterReturning来完成事务的提交操作,提交的具体逻辑是通过doCommit方法来实现的,实现的时候也要获取链接,通过链接对象来提交
- 当事务执行完毕之后需要清除相关的事务信息cleanupTransactionInfo
如果想要聊的更加细致的话,需要知道TransactionInfo,TransactionsStatus
Spring中用到的设计模式?
单例模式:bean默认都是单例的
工厂模式:BeanFactory
代理模式:动态代理
原型模式:指定作用域为prototype
模板模式:postProcessBeanFactory,onRefresh,initPropertyValue
策略模式:XmlBeanDefinitionReader,PropertiesBeanDefinitionReader
观察者模式:listener,event,multicast
适配器模式:Adapter
装饰者模式:BeanWrapper
责任链模式:使用aop的时候会生成一个拦截器
委托者模式:delegate