Spring八股文
反射
1、谈谈spring ioc的理解,原理和实现?
总:两层意思:控制反转和容器。
控制反转:他是一种思想理论,原来的对象是由我们使用者自己来进行控制的,而有了spring之后就把对象交给了spring来给我们进行管理;
容器:存放具体存储对象的。
分:
2、谈一下spring ioc的底层实现
3、描述一下bean的生命周期?就是bean从创建到销毁的全过程
1.实例化
a.通过反射去推断构造函数进行实例化
b.实例工厂、静态工厂
2.属性赋值
a.解析自动装配(byname bytype constractor none @Autowired) DI的体现 b.循环依赖
3.初始化
a.调用XXXAware回调方法
b.调用初始化生命周期回调(三种)
c.如果bean实现aop 创建动态代理
4.销毁
a.在spring容器关闭的时候进行调用
b.调用销毁生命周期回调
4、spring 是如何解决循环依赖问题的?
5、spring中用到的设计模式
6、spring的AOP底层实现原理?
7、spring 的事务是如何回滚的?
8、谈一下spring 的事务传播?
spring 是如何解决循环依赖问题的?
去看源码:DefaultSingletonBeanRegistry类中
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
//一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
//二级缓存
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
//三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}
//三级缓存中map储存的value
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
解决循环依赖问题
答:Spring通过三级缓存解决了循环依赖,其中一级缓存为单例池(singletonObjects),二级缓存为早期曝光对象earlySingletonObjects,三级缓存为早期曝光对象工厂(singletonFactories)。
一二级缓存使用的是ConcurrentHashMap(为了安全,bean默认是单例)
三级缓存用的是HashMap
三级缓存中,有一个方法用了synchronized修饰
当A、B两个类发生循环引用时,在A完成实例化后,就使用实例化后的对象去创建一个对象工厂,添加到三级缓存中,如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象。
当A进行属性注入时,会去创建B,同时B又依赖了A,所以创建B的同时又会去调用getBean(a)来获取需要的依赖,此时的getBean(a)会从缓存中获取:
❝第一步:先获取到三级缓存中的工厂;
第二步:调用对象工工厂的getObject方法来获取到对应的对象,得到这个对象后将其注入到B中。紧接着B会走完它的生命周期流程,包括初始化、后置处理器等。
第三步:当B创建完后,会将B再注入到A中,此时A再完成它的整个生命周期。至此,循环依赖结束!
❞
面试官:为什么要使用三级缓存呢?二级缓存能解决循环依赖吗?
❝答:如果要使用二级缓存解决循环依赖,意味着所有Bean在实例化后就要完成AOP代理,这样违背了Spring设计的原则,Spring在设计之初就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理,而不是在实例化后就立马进行AOP代理。
❞
Spring涉及的设计模式以及应用场景
【Spirng】8.spring框架中使用了哪些设计模式及应用场景_哔哩哔哩_bilibili
- 工厂模式,在各种BeanFactory以及ApplicationContext创建中都用到了
- 模版模式,在各种BeanFactory以及ApplicationContext实现中也都用到了
- 代理模式,Spring AOP利用了AspectJ AOP实现的! AspectJ AOP的底层用了动态代理
- 策略模式,加载资源文件的方式,使用了不同的方法,比如: ClassPathResourece,FileSystemResource,ServletContextResource,UrlResource但他们都有共同的借口Resource;在Aop的实现中,采用了两种不同的方式,JDK动态代理和CGLIB代理
- 单例模式,比如在创建bean的时候。
- 观察者模式,spring中的ApplicationEvent,ApplicationListener,ApplicationEventPublisher
- 适配器模式,MethodBeforeAdviceAdapter,ThrowsAdviceAdapter,AfterReturningAdapter
- 装饰者模式,源码中类型带Wrapper或者Decorator的都是
SpringBean的生命周期
1、解析xml配置或注解配置的类,得到BeanDefinition;
2、通过BeanDefinition反射创建Bean对象;
3、对Bean对象进行属性填充;
4、回调实现了Aware接口的方法,如BeanNameAware;
5、调用BeanPostProcessor的初始化前方法;
6、调用init初始化方法;
7、调用BeanPostProcessor的初始化后方法,此处会进行AOP;
8、将创建的Bean对象放入一个Map中;
9、业务使用Bean对象;
10、Spring容器关闭时调用DisposableBean的destory()方法;
Spring的核心是什么?
Spring是一个开源框架,他是为了简化企业开发而生的,更加优雅和简洁.
Spring是整个Spring生态中的基石,其他的框架都是在spring的基础上进行开发的
Spring 两大核心:IOC和AOP
IOC:
容器的一个创建过程.需要进行了解一下,拓展点,反射进行实例化....
IOC:是一种编程思想,原本对象的创建以及管理,都是由我们程序员自己来进行的,然后有了Spring之后呢,bean就交由Spring来替我们控制和进行管理,我们只需要专注于业务的处理就可以了,
IOC 是一种思想,如果问你DI是什么,他才是Spring的一个具体实现方式
容器
AOP:
面向切面编程 , 为 解耦 而生
当我们项目需要用到跟业务不相关的公共功能的时候,例如日志,事务配置,可以用到AOP,把一些关键的配置,插入到我们的业务代码中
Spring的事务隔离级别
基本跟Mysql的事务隔离级别差不多,7种
例如A类用了事务,A类里面用到了B类,B类里面也有事务
若此时事务级别是required 因为A类有事务,所以用A的事务
Spring是如何简化开发的
- 基于POJO的轻量级和最小侵入性编程
- 通过依赖注入和面向接口实现松耦合
- 他有很多自带的可拓展的接口,你可以进行实现重写其中的方法即可使用
- 基于切面和惯例进行声明式编程,只需要在方法上加上@Transactional注解即可
- 通过切面和模板减少样板式代码,
- 例如:你要在一些方法中切入一些日志,你只需要写好一个切面,告诉他在哪些方法中切入即可
Spring bean中的id和name是否可以重复
同名bean:多个bean 有相同的 name 或者 id,称之为同名bean
bean 的id 和 name的区别
id和name都是spring 容器中中bean 的唯一标识符。 name和id都不是必须的,可以没有
- id: 一个bean的唯一标识 , 命名格式必须符合XML ID属性的命名规范
- name: 可以用特殊字符,并且一个bean可以用多个名称:name=“bean1,bean2,bean3”
,用逗号或者分号或者空格隔开。如果没有id,则name的第一个名称默认是id
spring 容器如何处理同名bean?
- 同一个spring配置文件中,bean的 id、name是不能够重复的,否则spring容器启动时会报错。
如果一个spring容器从多个配置文件中加载配置信息,则多个配置文件中是允许有同名bean的,并且后面加载的配置文件的中的bean定义会覆盖前面加载的同名bean。
1、在spring同一个配置文件中,不能存在id相同的两个bean,否则会报错。
2、在两个不同的spring配置文件中,可以存在id相同的两个bean,启动时,不会报错。这是因为spring
ioc容器在加载bean的过程中,类DefaultListableBeanFactory会对id相同的bean进行处理:后加载的配置文件的bean,覆盖先加载的配置文件的bean。DefaultListableBeanFactory类中,有个属性allowBeanDefinitionOverriding,默认值为true,该值就是用来指定出现两个bean的id相同的情况下,如何进行处理。如果该值为false,则不会进行覆盖,而是抛出异常。
spring 容器如何处理没有指定id、name属性的bean?
如果 一个 bean 标签未指定 id、name 属性,则 spring容器会给其一个默认的id,值为其类全名。
如果有多个bean标签未指定 id、name 属性,则spring容器会按照其出现的次序,分别给其指定 id 值为 “类全名#1”, “类全名#2”
如下:
配置文件:
<bean class="com.xxx.UserInfo">
<property name="accountName" value="no-id-no-name0"></property>
</bean>
<bean class="com.xxx.UserInfo">
<property name="accountName" value="no-id-no-name1"></property>
</bean>
<bean class="com.xxx.UserInfo">
<property name="accountName" value="no-id-no-name2"></property>
</bean>
获取bean的方式:
UserInfo u4 = (UserInfo)ctx.getBean("com.xxx.UserInfo");
UserInfo u5 = (UserInfo)ctx.getBean("com.xxx.UserInfo#1");
UserInfo u6 = (UserInfo)ctx.getBean("com.xxx.UserInfo#2");
标签:面试题,缓存,Spring,常见,bean,spring,AOP,id
From: https://www.cnblogs.com/maomao777/p/16542373.html