内容分类 | 详情 |
---|---|
Java高频面试题 | 汇总入口 |
JVM | JVM面试题 |
并发 | 并发面试题 |
Spring | Spring面试题 |
分布式 | 分布式面试题 |
SpringBoot | SpringBoot面试题 |
SpringCloud | SpringCloud面试题 |
Dubbo | Dubbo面试题 |
MySQL | MySQL面试题 |
Mybatis | Mybatis面试题 |
Redis | Redis面试题 |
RocketMQ | RocketMQ面试题 |
算法 | 算法面试题 |
遇到的问题 | 遇到的问题 |
面试官的其他问题 | 面试官的其他问题 |
Git | Git面试题 |
文章目录
Spring对Bean加载过程,结合源码?
1.获取配置文件资源:
通过 ResourceLoader 来完成资源文件位置的定位,DefaultResourceLoader 是默认的实现, 同时上下文本身就给出了 ResourceLoader 的实现,可以从类路径、文件系统, URL 等方式 来定为资源位置。
2.对bean定义信息的解析:
容器通过 BeanDefinitionReader 来完成 bean 定义信息的解析,使 用的是 XmlBeanDefinitionReader 来解析 bean 的 xml 定义文件,实际的处理过程是委托给 BeanDefinitionParserDelegate 来完成的,从而得到 bean 的定义信息,这些信息在 Spring 中 使用 BeanDefinition 对象来表示
3.加载提取bean并注册(添加到beanDefinitionMap中):
IoC 容器 解析得到 BeanDefinition 以后,需要把它在 IoC 容器中注册,这由 IoC 实现 BeanDefinitionRegistry 接口来实现。注册过程就是在 IoC 容器内部维护的一个 HashMap 来保存得到的 BeanDefinition 的过程。这个 HashMap 是 IoC 容器持有 bean 信息的场所, 以后对 bean 的操作都是围绕这个 HashMap 来实现的。
4.bean的初始化:
通过DefaultListableBeanFactory的getBean()方法去初始化,实际由AbstractAutowireCapableBeanFactory的doCreateBean()去完成。
一个是创建 Bean 实例的 createBeanInstance 方法,一个是依赖注入的 populateBean 方法,还有就是回调方法 initializeBean。
// BeanPostProcessor两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization,两个方法分别在 Bean 初始化之前和初始化之后得到执行
Spring的AOP原理
AOP实现的核心技术是Java Proxy代理类、拦截器技术实现。
进入AOP代理核心类AnnotationAwareAspectJAutoProxyCreator,这个类实现了BeanPostProcessor接口,那就意味着这个类在spring加载实例化前会调用postProcessAfterInitialization方法,对于AOP的逻辑也是由此开始的。
1.spring 容器启动,每个bean的实例化之前都会先经过AbstractAutoProxyCreator类的postProcessAfterInitialization()这个方法,然后接下来是调用wrapIfNecessary方法。
2.进入wrapIfNecessary方法后,我们直接看重点实现逻辑的方法getAdvicesAndAdvisorsForBean,这个方法会提取当前bean 的所有增强方法,然后获取到适合的当前bean 的增强方法,然后对增强方法进行排序,最后返回Bean。
3.获取到当前bean的增强方法后,便调用createProxy方法,创建代理。先创建代理工厂proxyFactory,然后获取当前bean 的增强器advisors,把当前获取到的增强器添加到代理工厂proxyFactory,然后设置当前的代理工的代理目标对象为当前bean,最后根据配置创建JDK的动态代理工厂,或者CGLIB的动态代理工厂,然后返回proxyFactory
4.动态代理创建代理对象
Spring拦截器的实现原理
Spring的IOC原理
Spring如何解决循环依赖的
三级缓存每一级解决什么问题
getSingleton方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 2
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 3
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 4
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
singletonObjects 用来放完全初始化的bean
earlySingletonObjects 用来放实例化了,但还未完全初始化的bean
singletonFactories 则用来放代理bean
说明
1处,在最上层的缓存singletonObjects中,获取单例bean,这里面拿到的bean,直接可以使用;如果没取到,则进入2处
2处,在2级缓存earlySingletonObjects中,查找bean;
3处,如果在2级缓存中,还是没找到,则在3级缓存中查找对应的工厂对象,利用拿到的工厂对象(工厂对象中,有3个field,一个是beanName,一个是RootBeanDefinition,一个是已经创建好的,但还没有注入属性的bean),去获取包装后的bean,或者说,代理后的bean。
什么是已经创建好的,但没有注入属性的bean?
比如一个bean,有10个字段,你new了之后,对象已经有了,内存空间已经开辟了,堆里已经分配了该对象的空间了,只是此时的10个field还是null。
Spring事务传播
- REQUIRED(Spring默认的事务传播类型)
如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务
- SUPPORTS
当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
- MANDATORY(mandatory)强制性的
当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。
- REQUIRES_NEW
创建一个新事务,如果存在当前事务,则挂起该事务。
- NOT_SUPPORTED
始终以非事务方式执行,如果当前存在事务,则挂起当前事务
- NEVER
不使用事务,如果当前事务存在,则抛出异常
- NESTED(nested)
如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样(开启一个事务)
Spring事务失效的场景
-
方法是私有的
-
方法用final修饰
spring 事务底层使用了 aop,也就是通过 jdk 动态代理或者 cglib -
内部方法调用
@Service public class UserService { @Autowired private UserMapper userMapper; public void add(UserModel userModel) { userMapper.insertUser(userModel); updateStatus(userModel); } @Transactional public void updateStatus(UserModel userModel) { doSameThing(); } }
-
未被Spring管理
//@Service public class UserService { @Transactional public void add(UserModel userModel) { saveData(userModel); updateData(userModel); } }
-
多线程调用
@Slf4j @Service public class UserService { @Autowired private UserMapper userMapper; @Autowired private RoleService roleService; @Transactional public void add(UserModel userModel) throws Exception { userMapper.insertUser(userModel); new Thread(() -> { roleService.doOtherThing(); }).start(); } } @Service public class RoleService { @Transactional public void doOtherThing() { System.out.println("保存role表数据"); } }