【个人技术经验及开发技巧分享】 【个人技术经验及开发技巧分享】
首页
  • 操作系统初识
  • JAVA基础
  • JVM
  • 开发框架
  • Redis
  • Zookeeper
  • 消息中间件
  • 持久化
  • 算法
  • 网络
  • 系统架构
  • 并发编程
  • 框架
  • 开发杂货
  • 线上排查
  • 技巧备忘
  • 部署指南
  • 版本管理
  • 工作流程
  • 发版流程
  • 友情链接
  • 网站备忘
  • 在线工具
  • 学习
  • 各种云
  • 应用下载

Louis

首页
  • 操作系统初识
  • JAVA基础
  • JVM
  • 开发框架
  • Redis
  • Zookeeper
  • 消息中间件
  • 持久化
  • 算法
  • 网络
  • 系统架构
  • 并发编程
  • 框架
  • 开发杂货
  • 线上排查
  • 技巧备忘
  • 部署指南
  • 版本管理
  • 工作流程
  • 发版流程
  • 友情链接
  • 网站备忘
  • 在线工具
  • 学习
  • 各种云
  • 应用下载
  • 操作系统初识

  • JAVA基础

  • JVM

  • 开发框架

    • SpringMVC
    • Spring
      • 1 Spring常见问题
        • 1.1 BeanFactory与FactoryBean的区别?
        • 1.2 BeanFactory与ApplicationContext的区别?
        • 1.3 Spring整合Mybatis后为什么会导致一级缓存失效?
      • 2 Bean的生成过程
        • 2.1 生成BeanDefinition
        • 2.2 合并BeanDefinition
        • 2.3 加载类
        • 2.4 实例化前(扩展点)
        • 2.5 实例化
        • 2.6 BeanDefinition的后置处理(扩展点)
        • 2.7 实例化后(扩展点)
        • 2.8 处理属性
        • 2.9 执行Aware(扩展点)
        • 2.10 初始化前(扩展点)
        • 2.11 初始化
        • 2.12 初始化后(扩展点)
      • 3 Bean的销毁过程
      • 4 什么是循环依赖?
      • 5 详细讲下三级缓存?
        • 5.1 singletonObjects(一级缓存:单例池)
        • 5.2 earlySingletonObjects(二级缓存)
        • 5.3 singletonFactories(三级缓存)
        • 5.4 earlyProxyReferences
      • 6 为什么需要第三级缓存?
    • Mybatis
    • Sentinel
    • Spring Security Oauth2
    • SpringBoot
    • Spring Cloud Gateway
  • Redis

  • Zookeeper

  • 消息中间件

  • 持久化

  • 算法

  • 网络

  • 系统架构

  • 学习笔记
  • 开发框架
luoxiaofeng
2022-05-07
目录

Spring

# 1 Spring常见问题

# 1.1 BeanFactory与FactoryBean的区别?

BeanFactory

IOC容器的核心接口,负责生产和管理Spring中的Bean。 ApplicationContext就是BeanFactory的一种,继承了BeanFactory的功能,又扩展了很多其他功能。

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory,
        HierarchicalBeanFactory,
        MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
        //...
}
1
2
3
4
5

FactoryBean

也是一个接口,通过实现FactoryBean接口,可以创建一个我们自己定义的Bean,这个Bean只会经过Spring的Bean生命周期步骤中的初始化后,其他生命周期步骤不会经过。

提示

Spring整合Mybatis时,就是通过FactoryBean的方式,将Mybatis中的sql对应的接口转化成Spring的Bean对象。

@Component
public class TestFactoryBean implements FactoryBean {
  @Override
  public Object getObject() throws Exception {
    UserService userService = new UserService();
    return userService;
  }

  @Override
  public Class<?> getObjectType() {
    return UserService.class;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 1.2 BeanFactory与ApplicationContext的区别?

ApplicationContext由BeanFactory派生而来,拥有比BeanFactory更多的功能,比如:

1.支持国际化功能。

2.支持事件机制(发布订阅)。

3.支持底层资源访问,可以用来加载多个Resource。

4.支持web应用。

# 1.3 Spring整合Mybatis后为什么会导致一级缓存失效?

Mybatis的一级缓存是利用SqlSession实现的,同样的sql,如果在同一个SqlSession执行,就会利用一级缓存,提高查询效率。

Spring整合Mybatis后,执行方法时,如果方法没有加@Transactional注解,那么方法里面执行sql时,每个sql要执行时都会先生成一个新的SqlSession去执行该sql,所以一级缓存会失效。如果加上@Transactional注解,即开启事务,则同个方法内多个sql使用的是同一个SqlSession,从而一级缓存能生效。

# 2 Bean的生成过程

# 2.1 生成BeanDefinition

Spring启动的时候会进行扫描,扫描指定包路径下的所有.class文件,并得到BeanDefinition的Set集合。

Spring源码中将class文件包装成Resource对象,遍历每个Resource对象。解析.class文件利用的是ASM技术,并没有加载这个类到JVM。

什么是BeanDefinition?

Bean定义,存在很多属性来描述一个Bean的特点。比如:

class:表示bean类型。

scope:表示bean的作用域,如单例、原型等。

lazyInit:表示类是否懒加载。

initMethodName:表示Bean初始化时要执行的方法。

destroyMethodName:表示Bean销毁时要执行的方法。

# 2.2 合并BeanDefinition

Spring中支持父子BeanDefinition,child会继承parent上定义的属性。

# 2.3 加载类

加载BeanDefinition所对应的class。

# 2.4 实例化前(扩展点)

BeanDefinition对应的类成功加载后,就可以实例化对象了。但是在Spring中,实例化对象之前,Spring提供了一个扩展点:InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()

@Component
public class TestBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
      if ("userService".equals(beanName)) {
        System.out.println("实例化前"); 
      }
      return null;
    }
}
1
2
3
4
5
6
7
8
9
10

如果按上面例子,在实例化前直接返回一个自己定义的对象,则表示不需要Spring来实例化了,并且后面的Spring依赖注入也不会进行,会跳过一些步骤,直接执行到 初始化后 这一步。

# 2.5 实例化

根据BeanDefinition去创建一个对象。

1.BeanDefinition中是否设置了Supplier,如果设置了则调用Supplier的get()得到对象。

2.BeanDefinition中是否设置了factoryMethod,如果设置了则调用工厂方法得到对象。

3.创建对象前,推断构造方法。

# 2.6 BeanDefinition的后置处理(扩展点)

Bean对象实例化出来之后,接下来可以给对象属性赋值了。但是在赋值之前,Spring又提供了一个扩展点可以对此时的BeanDefinition进行加工:

MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()

@Component
public class TestMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
      if ("userService".equals(beanName)) {
        beanDefinition.getPropertyValues().add("orderService", new OrderService());
      }
    }
}  
1
2
3
4
5
6
7
8
9

# 2.7 实例化后(扩展点)

处理完BeanDefinition,Spring还提供一个扩展点处理实例对象:

InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()

@Component
public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
  @Override
  public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    if ("userService".equals(beanName)) {
      UserService userService = (UserService) bean;
      userService.test();
    }
    return true;
  }
}
1
2
3
4
5
6
7
8
9
10
11

# 2.8 处理属性

处理@Autowired、@Resource、@Value等注解,通过以下扩展点实现:

InstantiatiionAwareBeanPostProcessor.postProcessProperties()

我们甚至可以以此实现一个自己的注入功能,如:

@Component
public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
  @Override
  public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
    if ("userService".equals(beanName)) {
      for (Field field : bean.getClass().getFields()) {
        if (field.isAnnotationPresent(TestInject.class)) {
          field.setAccessible(true);
          try {
            field.set(bean, "abc");
          } catch (IllegalAccessException e) {
            e.printStackTrace();
          }
        }
      }
    }
    return pvs;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 2.9 执行Aware(扩展点)

完成属性赋值后,Spring会执行一些回调,包括:

1.BeanNameAware:回传beanName给bean对象。

2.BeanClassLoaderAware:回传classLoader给bean对象。

3.BeanFactoryAware:回传beanFactory给对象。

# 2.10 初始化前(扩展点)

Spring提供的一个扩展点:

BeanPostProcessor.postProcessBeforeInitialization()

@Component
public class TestBeanPostProcessor implements BeanPostProcessor {
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if ("userService".equals(beanName)) {
      System.out.println("初始化前");
    }
    return bean;
  }
}
1
2
3
4
5
6
7
8
9
10

在Spring源码中:

1.InitDestroyAnnotationBeanPostProcessor会在初始化前这个步骤中执行 @PostConstruct 的方法。

2.ApplicationContextAwareProcessor会在初始化前这个步骤进行其他Aware的回调:

1)EnvironmentAware:回传环境变量

2)EmbeddedValueResolverAware:回传占位符解析器

3)ResourceLoaderAware:回传资源加载器

4)ApplicationEventPublisherAware:回传事件发布器

5)MessageSourceAware:回传国际化资源

6)ApplicationStartupAware:回传应用其他监听对象,可忽略

7)ApplicationContextAware:回传Spring容器ApplicationContext

# 2.11 初始化

1.当前Bean对象是否实现了InitializingBean接口,实现了就调用其 afterPropertiesSet() 方法。

2.执行BeanDefinition中指定的初始化方法。

beanDefinition.setScope("prototype"); // 设置作用域
beanDefinition.setInitMethodName("init"); // 设置初始化方法
beanDefinition.setLazyInit(true); // 设置懒加载
1
2
3

# 2.12 初始化后(扩展点)

Bean创建生命周期中的最后一个步骤,Spring提供的一个扩展点:

BeanPostProcessor.postProcessAfterInitialization()

@Component
public class TestBeanPostProcessor implements BeanPostProcessor {
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if ("userService".equals(beanName)) {
      System.out.println("初始化后");
    }
    return bean;
  }
}
1
2
3
4
5
6
7
8
9
10

可以在这个步骤中对Bean进行最终处理。

Spring中的 AOP 就是基于 初始化后 实现的。 初始化后 返回的对象才是最终的Bean对象。

# 3 Bean的销毁过程

Bean销毁是发生在Spring容器关闭过程中的。

1.在Bean创建过程中,最后(初始化后)有一个步骤去判断当前创建的Bean是不是DisposableBean:

1)当前Bean是否实现了DisposableBean接口。

2)当前Bean是否实现了AutoCloseable接口。

3)BeanDefinition中是否指定了destroyMethod。

4)调用DestructionAwareBeanPostProcessor.requiresDestruction(bean)进行判断。

5)把符合上述任意一个条件的Bean适配成DisposableBeanAdapter对象,并存入disposableBeans中。其中disposableBeans是一个LinkedHashMap。

2.在Spring容器关闭过程时:

1)首先发布ContextClosedEvent事件。

2)调用lifecycleProcessor的onCloese()方法。

3)遍历disposableBeans销毁单例Bean。

# 4 什么是循环依赖?

A创建时 --> 需要B --> B去创建时 --> 需要A,从而产生循环。

如何打破循环,加个中间人(缓存)

实际上就是使用了三级缓存解决循环依赖。

# 5 详细讲下三级缓存?

# 5.1 singletonObjects(一级缓存:单例池)

缓存经过了完整生命周期的bean。

# 5.2 earlySingletonObjects(二级缓存)

缓存未经过完整生命周期的bean,只要某个bean出现了循环依赖,就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中(这个bean如果要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入earlySingletonObjects),即使是代理对象,代理对象所代理的原始对象也是没有经过完整生命周期的。

# 5.3 singletonFactories(三级缓存)

缓存的是一个Lambda表达式。在每个Bean的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达式,并保存到三级缓存中(这个Lambda表达式可能用到也可能用不到,如果当前Bean没有出现循环依赖,那么这个Lambda表达式没用)。如果当前bean在依赖注入时发现出现了循环依赖,则从三级缓存中拿到Lambda表达式,并执行Lambda表达式得到一个对象,并把得到的对象放入二级缓存。

# 5.4 earlyProxyReferences

其实还要一个缓存,就是earlyProxyReferences,它用来记录某个原始对象是否进行过AOP了。

# 6 为什么需要第三级缓存?

主要为了处理AOP的问题。

如果没有第三级缓存earlySingletonObjects,则每个bean在依赖注入之前都要去进行AOP的操作,不符合bean的生命周期步骤设计,即AOP对象是在初始化之后生成。

有第三级缓存,则没有循环依赖的需要AOP对象可以按bean的生命周期步骤进行,有循环依赖的需要AOP对象在依赖注入时通过三级缓存中Lambda表达式获取AOP对象放入二级缓存。初始化后要生成AOP对象时去判断是否已经生成过,已生成则不再处理。

#Spring
SpringMVC
Mybatis

← SpringMVC Mybatis→

最近更新
01
SpringBoot
10-21
02
Spring
10-20
03
Sentinel
10-14
更多文章>
Copyright © 2022-2023 Louis | 粤ICP备2022060093号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式