IOC容器

IOC就是控制反转,是指创建对象的控制权的转移,以前创建对象的权利全是交由用户来控制的,现在这种权利交由Spring容器控制,容器会根据配置文件去创建各个实例之间的依赖关系,实现了对象与对象之间的松耦合。实现原理是通过Java的反射来动态生成对象,注入方式一共有三种,分别是构造器注入,setter注入。

容器启动及配置类加载流程

  1. 容器的启动
    首先,调用BeanDefinitionReader加载配置文件,将内容映射到BeanDefinition中,解析配置文件,并将类型信息存储到BeanDefinition,交给BeanDefinitionRegistry管理,最后注册到BeanFactory。
    image-20200216160755482.png
  2. Bean实例化
    image-20200216160831271.png

创建过程

  1. 实例化bean对象,以及设置bean属性;
  2. 如果通过Aware接口声明了依赖关系,则会注入Bean对容器基础设施层面的依赖,Aware接口是为了感知到自身的一些属性。容器管理的Bean一般不需要知道容器的状态和直接使用容器。但是在某些情况下是需要在Bean中对IOC容器进行操作的。这时候需要在bean中设置对容器的感知。SpringIOC容器也提供了该功能,它是通过特定的Aware接口来完成的。 比如BeanNameAware接口,可以知道自己在容器中的名字。 如果这个Bean已经实现了BeanFactoryAware接口,可以用这个方式来获取其它Bean。 (如果Bean实现了BeanNameAware接口,调用setBeanName()方法,传入Bean的名字。 如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。 如果Bean实现了BeanFactoryAware接口,调用setBeanFactory()方法,传入BeanFactory对象的实例。)
  3. 紧接着会调用BeanPostProcess的前置初始化方法postProcessBeforeInitialization,主要作用是在Spring完成实例化之后,初始化之前,对Spring容器实例化的Bean添加自定义的处理逻辑。有点类似于AOP。
  4. 如果实现了BeanFactoryPostProcessor接口的afterPropertiesSet方法,做一些属性被设定后的自定义的事情。
  5. 调用Bean自身定义的init方法,去做一些初始化相关的工作。
  6. 调用BeanPostProcess的后置初始化方法,postProcessAfterInitialization去做一些bean初始化之后的自定义工作。
  7. 完成以上创建之后就可以在应用里使用这个Bean了。

销毁过程
当Bean不再用到,便要销毁 。

  1. 若实现了DisposableBean接口,则会调用destroy方法;
  2. 若配置了destry-method属性,则会调用其配置的销毁方法。

    Bean的作用域

    image-20200216163534360.png

自动装配的方式

当 bean 在 Spring 容器中组合在一起时,它被称为装配或 bean 装配。 Spring 容器需要知道需要什么 bean 以及容器应该如何使用依赖注入来将 bean 绑定在一起,同时装配 bean。
Spring 容器能够自动装配 bean。也就是说,可以通过检查 BeanFactory 的内容让 Spring 自动解析 bean 的协作者。

  • no:不进行自动装配,手动设置Bean的依赖关系。
  • byName:根据Bean的名字进行自动装配。
  • byType:根据Bean的类型进行自动装配。
  • constructor:类似于byType,不过是应用于构造器的参数,如果正好有一个Bean与构造器的参数类型相同则可以自动装配,否则会导致错误。
  • autodetect:如果有默认的构造器,则通过constructor的方式进行自动装配,否则使用byType的方式进行自动装配。

缺点

  • 覆盖的可能性 - 您始终可以使用 和 设置指定依赖项,这将覆盖自动装配。
  • 基本元数据类型 - 简单属性(如原数据类型,字符串和类)无法自动装配。
  • 令人困惑的性质 - 总是喜欢使用明确的装配,因为自动装配不太精确。

    IOC和DI

    IoC叫控制反转,是Inversion of Control的缩写,通俗的说就是我们不用自己创建实例对象,这些都交给Spring的bean工厂帮我们创建管理。这也是Spring的核心思想,通过面向接口编程的方式来是实现对业务组件的动态依赖。这就意味着IOC是Spring针对解决程序耦合而存在的。DI(Dependency Injection)叫依赖注入,是对IoC更简单的诠释。DI即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。

依赖注入可以通过setter方法注入(设值注入)、构造器注入和接口注入三种方式来实现,Spring支持setter注入和构造器注入,通常使用构造器注入来注入必须的依赖关系,对于可选的依赖关系,则setter注入是更好的选择,setter注入需要类提供无参构造器或者无参的静态工厂方法来创建对象。

构造器注入和Setter注入的区别

构造函数注入 Setter注入
没有部分注入 有部分注入
不会覆盖 setter 属性 会覆盖 setter 属性
任意修改都会创建一个新实例 任意修改不会创建一个新实例
适用于设置很多属性 适用于设置少量属性

BeanFactory和ApplicationContext的区别

  • BeanFactory
    BeanFactory是spring中比较原始,比较古老的Factory。因为比较古老,所以BeanFactory无法支持spring插件,例如:AOP、Web应用等功能。
  • ApplicationContext
    ApplicationContext是BeanFactory的子接口,因为古老的BeanFactory无法满足不断更新的spring的需求,于是ApplicationContext就基本上代替了BeanFactory的工作,以一种更面向框架的工作方式以及对上下文进行分层和实现继承,并在这个基础上对功能进行扩展:
    • MessageSource, 提供国际化的消息访问;
    • 资源访问(如URL和文件);
    • 事件传递;
    • Bean的自动装配;
    • 各种不同应用层的Context实现。

区别:

BeanFactory ApplicationContext
不支持AOP、WEB 支持AOP、WEB
懒汉式加载Bean 饿汉式加载单例
使用语法显式提供资源对象 自己创建和管理资源对象
不支持国际化 支持国际化
不支持基于依赖的注解 支持基于依赖的注解

BeanFactory的优缺点:

  • 优点:应用启动的时候占用资源很少,对资源要求较高的应用,比较有优势;
  • 缺点:运行速度会相对来说慢一些。而且有可能会出现空指针异常的错误,而且通过Bean工厂创建的Bean生命周期会简单一些。

ApplicationContext的优缺点:

  • 优点:所有的Bean在启动的时候都进行了加载,系统运行的速度快;在系统启动的时候,可以发现系统中的配置问题。
  • 缺点:把费时的操作放到系统启动中完成,所有的对象都可以预加载,缺点就是内存占用较大。

    创建Bean的几种方式

  1. 使用xml配置(不利于对象管理)
    1. <bean id="xxxx" class="xxxx.xxxx"/>
  1. 使用注解@Component,@Service,@Controller,@Repository
    @Component:侧重于通用的Bean类;
    @Service:标识该类用于业务逻辑;
    @Controler:标识该类为Spring MVC的控制器类;
    @Repository:标识该类是一个实体类,只有属性和Setter,Getter。它为 DAO 提供了额外的好处。它将 DAO 导入 IOC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。
  2. 使用@Bean注解
  3. 使用@Import
    1. @Import(User.class)
    2. public class MicroblogUserWebApplication {
    3. public static void main(String args[]) {
    4. SpringApplication.run(MicroblogUserWebApplication.class, args);
    5. }
    6. }
  1. 手动注入 ```java @Component public class LocationRegister implements BeanFactoryAware {

    @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException {

    1. DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory)beanFactory;

        //方式1     Location location = new Location();    listableBeanFactory.registerSingleton(Location.class.getName(),location);

    //方式2     BeanDefinition locationBeanDefinition = new RootBeanDefinition(Location.class);     listableBeanFactory.registerBeanDefinition(Location.class.getName(),locationBeanDefinition); } }

  1. <a name="QjAXS"></a>
  2. #### Spring中的单例bean的线程安全问题
  3. 当多个用户同时请求一个服务时,容器会给每一个请求分配一个线程,这时多个线程会并发执行该请求对应的业务逻辑(成员方法),此时就要注意了,如果该处理逻辑中有对单例状态的修改(体现为该单例的成员属性),则必须考虑线程同步问题。 **线程安全问题都是由全局变量及静态变量引起的。** 若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全.<br />**无状态bean和有状态bean**
  4. - 有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。
  5. - 无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象 .不能保存数据,是不变类,是线程安全的。
  6. 在spring中无状态的Bean适合用不变模式,就是单例模式,这样可以共享实例提高性能。有状态的Bean在多线程环境下不安全,适合用[Proto](/jump/super-jump/word?word=Proto)type原型模式。 Spring使用ThreadLocal解决线程安全问题。如果你的Bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全 。
  7. <a name="77b59385"></a>
  8. #### 实例化Bean的源码分析
  9. 以单例为例:
  10. <a name="56a51423"></a>
  11. ##### DefaultSingletonBeanRegistry#getSingleton()
  12. ```java
  13. public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
  14. Assert.notNull(beanName, "Bean name must not be null");
  15. synchronized (this.singletonObjects) {
  16. Object singletonObject = this.singletonObjects.get(beanName);
  17. if (singletonObject == null) {
  18. ...
  19. try {
  20. // 从单例工厂获取实例对象
  21. singletonObject = singletonFactory.getObject();
  22. newSingleton = true;
  23. }
  24. catch (IllegalStateException ex) {
  25. ...
  26. }
  27. ...
  28. return singletonObject;
  29. }
  30. }

主要通过singletonFactory.getObject()方法来获取实例Bean,其中,getObject()主要调用了AbstractBeanFactory的doGetBean()方法。

AbstractBeanFactory#doGetBean()
  1. if (mbd.isSingleton()) {
  2. sharedInstance = getSingleton(beanName, () -> {
  3. try {
  4. return createBean(beanName, mbd, args);
  5. }
  6. catch (BeansException ex) {
  7. destroySingleton(beanName);
  8. throw ex;
  9. }
  10. });
  11. ...
  12. }

这段代码主要是调用了createBean()方法。

AbstractAutowireCapableBeanFactory#createBean
  1. @Override
  2. protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
  3. throws BeanCreationException {
  4. ...
  5. // 根据设置的class属性或className来解析得到class引用
  6. Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
  7. ...
  8. try {
  9. // 处理InstantiationAwareBeanPostProcessor
  10. Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
  11. if (bean != null) {
  12. return bean;
  13. }
  14. }
  15. catch (Throwable ex) {
  16. ...
  17. }
  18. try {
  19. // 创建bean实例
  20. Object beanInstance = doCreateBean(beanName, mbdToUse, args);
  21. ...
  22. return beanInstance;
  23. }
  24. catch (BeanCreationException ex) {
  25. ...
  26. }
  27. }

createBean解析class并得到class的引用,并做了一些前置后置处理器的初始化,随后会进入doCreateBean()。

AbstractAutowireCapableBeanFactory#doCreateBean()
  1. 如果是单例,尝试从缓存中获取 bean 的包装器 BeanWrapper
  2. 如果不存在对应的 Wrapper,则说明 bean 未被实例化,创建 bean 实例
  3. 应用 MergedBeanDefinitionPostProcessor
  4. 检查是否需要提前曝光,避免循环依赖
  5. 初始化 bean 实例
  6. 再次基于依存关系验证是否存在循环依赖
  7. 注册 DisposableBean
  1. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
  2. throws BeanCreationException {
  3. BeanWrapper instanceWrapper = null;
  4. // 如果是单例,尝试获取对应的Bean包装器
  5. if (mbd.isSingleton()) {
  6. instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
  7. }
  8. if (instanceWrapper == null) {
  9. /*
  10. * 说明对应的bean还没有创建,用对应的策略(工厂方法、构造函数)创建bean实例,以及简单初始化
  11. *
  12. * 将beanDefinition转成BeanWrapper,大致流程如下:
  13. * 1. 如果存在工厂方法,则使用工厂方法初始化
  14. * 2. 否则,如果存在多个构造函数,则根据参数确定构造函数,并利用构造函数初始化
  15. * 3. 否则,使用默认构造函数初始化
  16. */
  17. instanceWrapper = createBeanInstance(beanName, mbd, args);
  18. }
  19. final Object bean = instanceWrapper.getWrappedInstance();
  20. // 获取class引用
  21. Class<?> beanType = instanceWrapper.getWrappedClass();
  22. if (beanType != NullBean.class) {
  23. mbd.resolvedTargetType = beanType;
  24. }
  25. // 应用MergedBeanDefinitionPostProcessor
  26. synchronized (mbd.postProcessingLock) {
  27. if (!mbd.postProcessed) {
  28. try {
  29. applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
  30. }
  31. catch (Throwable ex) {
  32. ...
  33. }
  34. mbd.postProcessed = true;
  35. }
  36. }
  37. // 检查是否需要提前曝光,避免循环依赖
  38. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
  39. if (earlySingletonExposure) {
  40. ...
  41. // 添加一级缓存
  42. addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
  43. }
  44. // 初始化Bean实例
  45. Object exposedObject = bean;
  46. try {
  47. // 属性填充
  48. populateBean(beanName, mbd, instanceWrapper);
  49. // 调用初始化方法
  50. exposedObject = initializeBean(beanName, exposedObject, mbd);
  51. }
  52. catch (Throwable ex) {
  53. ...
  54. }
  55. // 在此基于依存关系验证是否存在循环依赖
  56. if (earlySingletonExposure) {
  57. // 提前曝光
  58. Object earlySingletonReference = getSingleton(beanName, false);
  59. if (earlySingletonReference != null) {
  60. // 检测到循环依赖
  61. if (exposedObject == bean) {
  62. exposedObject = earlySingletonReference;
  63. }
  64. else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
  65. // 获取依赖的bean name
  66. String[] dependentBeans = getDependentBeans(beanName);
  67. Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
  68. for (String dependentBean : dependentBeans) {
  69. // 检测依赖,记录未完成创建的bean
  70. if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
  71. actualDependentBeans.add(dependentBean);
  72. }
  73. }
  74. // 不为空说明bean依赖的bean没有创建,存在循环依赖
  75. if (!actualDependentBeans.isEmpty()) {
  76. throw new BeanCurrentlyInCreationException(...);
  77. }
  78. }
  79. }
  80. }
  81. //注册DisposableBean
  82. try {
  83. registerDisposableBeanIfNecessary(beanName, bean, mbd);
  84. }
  85. catch (BeanDefinitionValidationException ex) {
  86. ...
  87. }
  88. return exposedObject;
  89. }

AbstractAutowireCapableBeanFactory#populateBean
  1. protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
  2. if (bw == null) {
  3. ...
  4. }
  5. boolean continueWithPropertyPopulation = true;
  6. // 给InstantiationAwareBeanPostProcessors最后一次机会在注入属性前改变bean实例
  7. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
  8. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  9. if (bp instanceof InstantiationAwareBeanPostProcessor) {
  10. InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
  11. if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
  12. continueWithPropertyPopulation = false;
  13. break;
  14. }
  15. }
  16. }
  17. }
  18. // 如果处理器指明不需要再继续执行属性注入,则返回
  19. if (!continueWithPropertyPopulation) {
  20. return;
  21. }
  22. PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
  23. // autowire by name or autowire by type
  24. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
  25. mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
  26. MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
  27. // autowire by name
  28. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
  29. autowireByName(beanName, mbd, bw, newPvs);
  30. }
  31. // autowire by type
  32. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
  33. autowireByType(beanName, mbd, bw, newPvs);
  34. }
  35. pvs = newPvs;
  36. }
  37. boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
  38. boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
  39. // 在属性注入前应用实例化后置处理器
  40. if (hasInstAwareBpps || needsDepCheck) {
  41. if (pvs == null) {
  42. pvs = mbd.getPropertyValues();
  43. }
  44. PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
  45. if (hasInstAwareBpps) {
  46. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  47. if (bp instanceof InstantiationAwareBeanPostProcessor) {
  48. InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
  49. // 调用后置处理器的postProcessPropertyValues方法
  50. pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
  51. if (pvs == null) {
  52. return;
  53. }
  54. }
  55. }
  56. }
  57. if (needsDepCheck) {
  58. checkDependencies(beanName, mbd, filteredPds, pvs);
  59. }
  60. }
  61. // 执行属性注入
  62. if (pvs != null) {
  63. applyPropertyValues(beanName, mbd, bw, pvs);
  64. }
  65. }

该方法会执行 InstantiationAwareBeanPostProcessor 后置处理器的 postProcessAfterInstantiation 方法逻辑,从而实现对完成实例化且还没有注入属性值的对象进行最后的更改。

如果我们在 postProcessAfterInstantiation 指明不需要执行后续的属性注入过程,则方法到此结束;否则方法会检测当前的注入类型,是 byName 还是 byType,并调用相应的注入逻辑获取依赖的 bean,加入属性集合中。然后方法会调用 InstantiationAwareBeanPostProcessor 后置处理器的 postProcessPropertyValues 方法,实现在将属性值应用到 bean 实例之前的最后一次对属性值的更改,同时会依据配置执行依赖检查,以确保所有的属性都被赋值。

接下来我们看看真正的属性赋值操作。

AbstractAutowireCapableBeanFactory#applyPropertyValues
  1. protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
  2. ...
  3. // 获取对应的解析器
  4. BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
  5. // 深度拷贝
  6. List<PropertyValue> deepCopy = new ArrayList<>(original.size());
  7. boolean resolveNecessary = false;
  8. // 遍历属性,将属性转换成对应类的属性类型
  9. for (PropertyValue pv : original) {
  10. if (pv.isConverted()) {
  11. deepCopy.add(pv);
  12. }
  13. else {
  14. // 执行类型转换
  15. String propertyName = pv.getName();
  16. Object originalValue = pv.getValue();
  17. Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
  18. Object convertedValue = resolvedValue;
  19. boolean convertible = bw.isWritableProperty(propertyName) &&
  20. !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
  21. if (convertible) {
  22. convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
  23. }
  24. // Possibly store converted value in merged bean definition,
  25. // in order to avoid re-conversion for every created bean instance.
  26. if (resolvedValue == originalValue) {
  27. if (convertible) {
  28. pv.setConvertedValue(convertedValue);
  29. }
  30. deepCopy.add(pv);
  31. }
  32. else if (convertible && originalValue instanceof TypedStringValue &&
  33. !((TypedStringValue) originalValue).isDynamic() &&
  34. !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
  35. pv.setConvertedValue(convertedValue);
  36. deepCopy.add(pv);
  37. }
  38. else {
  39. resolveNecessary = true;
  40. deepCopy.add(new PropertyValue(pv, convertedValue));
  41. }
  42. }
  43. }
  44. if (mpvs != null && !resolveNecessary) {
  45. mpvs.setConverted();
  46. }
  47. try {
  48. // 设置值
  49. bw.setPropertyValues(new MutablePropertyValues(deepCopy));
  50. }
  51. catch (BeansException ex) {
  52. ...
  53. }
  54. }

使用深拷贝完成了属性的注入。属性注入完成后执行的是initializeBean()方法。

AbstractAutowireCapableBeanFactory#initializeBean
  1. 激活 bean 实现的 Aware 类:BeanNameAware, BeanClassLoaderAware, BeanFactoryAware
  2. 应用 BeanPostProcessor 的 postProcessBeforeInitialization
  3. 激活用户自定义的 init-method 方法,以及常用的 afterPropertiesSet 方法
  4. 应用 BeanPostProcessor 的 postProcessAfterInitialization
  1. protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
  2. // 1. 激活bean实现的Aware类:BeanNameAware, BeanClassLoaderAware, BeanFactoryAware
  3. if (System.getSecurityManager() != null) {
  4. AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
  5. invokeAwareMethods(beanName, bean);
  6. return null;
  7. }, getAccessControlContext());
  8. }
  9. else {
  10. invokeAwareMethods(beanName, bean);
  11. }
  12. // 2. 应用 BeanPostProcessor 的 postProcessBeforeInitialization
  13. Object wrappedBean = bean;
  14. if (mbd == null || !mbd.isSynthetic()) {
  15. wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  16. }
  17. // 3. 激活用户自定义的 init-method 方法,以及常用的 afterPropertiesSet 方法
  18. try {
  19. invokeInitMethods(beanName, wrappedBean, mbd);
  20. }
  21. catch (Throwable ex) {
  22. throw new BeanCreationException(
  23. (mbd != null ? mbd.getResourceDescription() : null),
  24. beanName, "Invocation of init method failed", ex);
  25. }
  26. // 4. 应用 BeanPostProcessor 的 postProcessAfterInitialization
  27. if (mbd == null || !mbd.isSynthetic()) {
  28. wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  29. }
  30. return wrappedBean;
  31. }

总结

首先,从Singleton工厂获取对象,随后进入createBean()方法,执行相关前置和后置处理器的初始化;处理完成后,调用doCrateBean的createBeanInstance进行Bean实例化操作;通过populateBean和applyPropertyValues进行属性注入,然后使用initializeBean激活Bean实现的Aware类,并检查循环依赖相关的逻辑,如果有必要,还会注册DisposableBean。

Spring中出现同名Bean怎么办

  • 同一个配置文件内同名的Bean,以最上面定义的为准
  • 不同配置文件中存在同名Bean,后解析的配置文件会覆盖先解析的配置文件
  • 同文件中ComponentScan和@Bean出现同名Bean。同文件下@Bean的会生效,@ComponentScan扫描进来不会生效。通过@ComponentScan扫描进来的优先级是最低的,原因就是它扫描进来的Bean定义是最先被注册的

    循环依赖

    循环依赖:当Bean A依赖于Bean B时,而Bean B也正好依赖于Bean A。
    spring对循环依赖的处理有三种情况: ①构造器的循环依赖:这种依赖spring是处理不了的,直 接抛出BeanCurrentlylnCreationException异常。 ②单例模式下的setter循环依赖:通过“三级缓存”处理循环依赖。 ③非单例循环依赖:无法处理。
    Spring单例对象初始化主要步骤如下:
  1. createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象;
  2. populateBean:填充属性,这一步主要是多bean的依赖属性进行填充;
  3. initializeBean:调用spring xml中的init 方法。

循环依赖主要发生在第一、二步,分别是构造器循环依赖和field循环依赖。在这里,引入了一个三级缓存的概念,源码在DefaultSingletonBeanRegistry类中:

  1. /** Cache of singleton objects: bean name --> bean instance */
  2. private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
  3. /** Cache of singleton factories: bean name --> ObjectFactory */
  4. private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
  5. /** Cache of early singleton objects: bean name --> bean instance */
  6. private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

三级缓存从里到外分别是:

  • singletonFactories : 单例对象工厂的cache;
  • earlySingletonObjects :提前曝光的单例对象的Cache;
  • singletonObjects:单例对象的cache。

具体获取Bean的代码在DefaultSingletonBeanRegistry的getSingleton()方法中:

  1. @Nullable
  2. protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  3. // 先从最外层缓存获取
  4. Object singletonObject = this.singletonObjects.get(beanName);
  5. if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
  6. synchronized (this.singletonObjects) {
  7. singletonObject = this.earlySingletonObjects.get(beanName);
  8. if (singletonObject == null && allowEarlyReference) {
  9. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
  10. if (singletonFactory != null) {
  11. singletonObject = singletonFactory.getObject();
  12. this.earlySingletonObjects.put(beanName, singletonObject);
  13. this.singletonFactories.remove(beanName);
  14. }
  15. }
  16. }
  17. }
  18. return singletonObject;
  19. }

那么一级缓存是什么时候添加的呢,细心的读者一定可以发现,在doCreateBean()方法中,createBeanInstance之后,属性注入之前,有一步:addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));,只要完成了实例化,就直接曝光,这就是所谓的早期引用概念。

值得注意的是,早期引用只能解决Setter注入的循环依赖问题,对于构造器注入和多实例的循环依赖问题是没有办法解决的。可以使用@Lazy注解进行懒加载来解决。

前置后置处理器

具体使用例子如下:

  1. public class InitHelloWorld implements BeanPostProcessor{
  2. public Object postProcessBeforeInitialization(Object bean,String beanName) {
  3. System.out.println("BeforeInitialization:"+beanName);
  4. return bean; // you can return any other object as well
  5. }
  6. public Object postProcessAfterInitialization(Object bean,String beanName) {
  7. System.out.println("AfterInitialization:"+beanName);
  8. return bean; // you can return any other object as well
  9. }
  10. }

首先需要实现BeanPostProcessor接口,然后重写前置和后置逻辑,最后需要在xml文件中进行配置:

  1. <bean class = "com.lamarsan.InitHelloWorld"></bean>

AOP

Spring AOP是面向切面编程,它的单元是切面,我们可以对切面做一些增强,同时它有利于代码的维护。AOP的实现方式主要有基于jdk的动态代理以及基于cglib的动态代理,我们可以用基于xml配置以及AspectJ注解来实现Spring AOP。好处是减少重复代码,提高开发效率,并且便于维护。

相关概念术语

  • 连接点(Joinpoint)
    程序执行的某个特定位置(如:某个方法调用前、调用后,方法抛出异常后)。Spring仅支持方法的连接点。
  • 增强(Advice)
    增强是织入到目标类连接点上的一段程序代码
  • 引介(Introduction)
    引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的未该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
  • 切点(Pointcut)
    查询条件,一个切点可以匹配多个连接点。Spring AOP的规则解析引擎负责解析切点所设定的查询条件,找到对应的连接点。
  • 切面(Aspect)
    切面是由切点增强(引介)组成的,它包括了对横切关注功能的定义,也包括了对连接点的定义。
  • 织入(Weaving)
    织入是将增强添加到目标类具体连接点上的过程,AOP有三种织入方式:
    1. 编译期织入:需要特殊的Java编译期(例如AspectJ的ajc);
    2. 装载期织入:要求使用特殊的类加载器,在装载类的时候对类进行增强;
    3. 运行时织入:在运行时为目标类生成代理实现增强。

Spring采用了动态代理的方式实现了运行时织入,而AspectJ采用了编译期织入和装载期织入的方式。

AOP的原理

AOP代理主要分为静态代理动态代理

  • 静态代理
    静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。通常使用AspectJ的编译时增强实现AOP,AspectJ是静态代理的增强,所谓的静态代理就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强。
  • 动态代理
    Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。
    JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口
    如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

    Spring事务隔离级别和事务传播属性

    隔离级别

  • DEFAULT(默认),使用数据库默认的隔离级别

  • READ_UNCOMMITTED(读未提交)
  • READ_COMMITTED(读已提交)
  • REPEATABLE_READ(可重复读)
  • SERIALIZABLE(串行化)

    传播属性

  • REQUIRED(默认)
    如果存在一个事务,则支持当前事务,没有就开启一个新的事务。

  • REQUIRES_NEW
    新建一个事务,如果当前存在事务,就挂起。
  • MANDATORY
    支持当前事务,如果没有事务就抛出异常。
  • NEVER
    以非事务方式运行,如果存在事务就抛出异常。
  • NOT_SUPPORTED
    以非事务方式执行操作,如果当前存在事务,就挂起。
  • SUPPORTS
    支持当前事务,如果当前没有事务,就以非事务方式执行。
  • NESTED(嵌套事务)
    支持当前事务,新增Savepoint,与当前事务同步提交或回滚。

    Spring声明式事务原理

    当声明了@Transaction之后,首先会使用拦截器TransactionInterceptor进行拦截,调用invoke,然后调用父类的invokeWithinTransaction方法:

    1. public Object invoke(MethodInvocation invocation) throws Throwable {
    2. Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
    3. // Adapt to TransactionAspectSupport's invokeWithinTransaction...
    4. return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
    5. }

    原理

    在应用系统调用声明@Transactional 的目标方法时,Spring Framework ,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常,利用抽象事务管理器AbstractPlatformTransactionManager 操作数据源 DataSource 提交或回滚事务。
    失效原因

  1. @Transactional注解应用到非public方法(除非特殊配置,例如使用AspectJ 静态织入实现 AOP);
  2. 自调用,因为@Transactional是基于动态代理实现的;
  3. 异常在代码中被你自己try catch了;
  4. 异常类型不正确,默认只支持RuntimeException和Error,不支持检查异常;
  5. 事务传播配置不符合业务逻辑。

由于基于动态代理实现(实现接口),因此修饰接口的必须是public类型,非public类型可以用AspectJ。
image.png

Spring事务管理有哪些优点

  • 它提供了跨不同事务api(如JTA、JDBC、Hibernate、JPA和JDO)的一致编程模型。
  • 它为编程事务管理提供了比JTA等许多复杂事务API更简单的API。
  • 它支持声明式事务管理。
  • 它很好地集成了Spring的各种数据访问抽象。

    Spring中的设计模式

  1. 简单工厂模式
    简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类,不属于23种设计模式之一。Spring 中的 BeanFactory 就是简单工厂模式的体现,根据传入一个唯一的标识来获得 Bean 对象。
  2. 工厂方法模式
    应用程序将对象的创建及初始化职责交给工厂对象。 一般情况下,应用程序有自己的工厂对象来创建 Bean。
  3. 单例模式
    保证一个类仅有一个实例,并提供一个访问它的全局访问点。 Spring 中的单例模式完成了后半句话,即提供了全局的访问点 BeanFactory。但没有从构造器级别去 控制单例,这是因为 Spring 管理的是是任意的 Java 对象。 Spring 下默认的 Bean 均为单例。
  4. 原型模式
    原型模式就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。如在IOC为Bean注入属性的时候,会使用深拷贝,就是一个原型模式的体现。
  5. 代理模式
    为其他对象提供一种代理以控制对这个对象的访问。Spring 的 Proxy 模式在 AOP 中有体现,比如 JdkDynamicAopProxy 和 Cglib2AopProxy。
  6. 策略模式
    定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换,使最终结果是固定的。Spring 中在实例化对象的时候用到 Strategy 模式,在 SimpleInstantiationStrategy 有使用。
  7. 模板方法模式
    定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Spring 中的 JdbcTemplate就是用的模板模式。
  8. 适配器模式
    注重转换。前端控制器DispatcherServlet可以把它理解为适配器模式中的Client,它的主要作用在于通过处理映射器(HandlerMapper)来找到相应的Handler,然后通过适配器去找到对应的Controller,并执行Controller中相应的方法并返回ModelAndView。如果不使用适配器接口,就要多许多if,else判断了,违反开闭原则。
  9. 装饰器模式
    主要用于扩展功能。所有以Wrapper和Decorator结尾的类名都是。
  10. 观察者模式
    定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象 都得到通知并被自动更新。Spring 中 Observer 模式常用的地方是 Listener 的实现。如 ApplicationListener。