Spring面试题

内容分类详情
Java高频面试题汇总入口
JVMJVM面试题
并发并发面试题
SpringSpring面试题
分布式分布式面试题
SpringBootSpringBoot面试题
SpringCloudSpringCloud面试题
DubboDubbo面试题
MySQLMySQL面试题
MybatisMybatis面试题
RedisRedis面试题
RocketMQRocketMQ面试题
算法算法面试题
遇到的问题遇到的问题
面试官的其他问题面试官的其他问题
GitGit面试题

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事务失效的场景

  1. 方法是私有的

  2. 方法用final修饰
    spring 事务底层使用了 aop,也就是通过 jdk 动态代理或者 cglib

  3. 内部方法调用

    @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();
        }
    }
    
  4. 未被Spring管理

    //@Service
    public class UserService {
    
        @Transactional
        public void add(UserModel userModel) {
            saveData(userModel);
            updateData(userModel);
        }    
    }
    
  5. 多线程调用

    @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表数据");
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gzh-程序员灿灿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值