抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

Spring IOC

IOC (Inversion of Control) :控制反转,是一种思想,不是技术。将原本在程序中手动创建对象的控制权,交由程序来管理。

  • Spring Core 最核心的部分。
  • 需要先了解依赖注入(Dependency Inversion)

什么是 DI

上层建筑依赖下层建筑. 从上到下创建.(依赖方向)

DI 来实现 IOC.

含义 : 把底层类作为参数传递给上层类, 实现上层对下层的”控制”. 从下到上开始创建(注入)。

IOC, DI, DL(Dependency Lookup, 依赖查找)的关系.

依赖注入的方式

  • Setter, Set方法
  • Interface, 接口
  • Constructor, 构造器
  • Annotation, 注解

依赖倒置原则, IOC, DI, IOC容器的关系

依赖倒置原则 : 高层模块不应该依赖底层模块, 两者应该依赖抽象.

有了这个思想才有了 IOC, 而 IOC 的实现 依靠 依赖注入 的支撑.

基于 IOC 提出了 IOC容器 概念, 容器管理 bean 的生命周期, 控制着 bean依赖注入.

IOC 容器的优势:

  • 避免了在各处使用 new 来创建类, 并且可以做到统一维护. 这个容器会自动对代码进行初始, 你需要维护一个 Configuration 就可以了.
  • 创建实例的时候不需要了解其中的细节.

上面的例子, 是从下往上 new 的.

IOC容器如下, 蓝色部分是隐藏的细节.

Spring IOC 原理

利用 Java 的反射功能实例化 bean.

Spring IOC 支持的功能

  • 依赖注入
  • 依赖检查
  • 自动装配
  • 支持集合
  • 指定初始化方法销毁方法
  • 支持回调方法(要实现接口, 略带侵略性)

Spring IOC 容器的核心接口

  • BeanFactory
  • ApplicationContext

BeanDefinition

  • 主要用来描述Bean的定义(把注解的类或者是xml配置的类解析)

BeanDefinitionRegistry

是一个接口.

  • 提供向 IOC 容器注册BeanDefinition对象的方法

默认注册到DefaultListableBeanFactory.

/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

BeanFactory

Spring 框架最核心的接口

  • 提供 IOC 的配置机制
  • 包含 Bean 的各种定义, 便以实例化 Bean
  • 建立 Bean 之间的依赖关系
  • Bean 生命周期的控制

BeanFactory是顶级容器接口, DefaultListableBeanFactoryBeanDefinitionRegistry都是从它扩展来的.

  • ListableBeanFactory : 定义了访问容器中 Bean 基本信息的若干方法, 如查看 Bean 的个数, 获取某一类型 Bean 的配置名, 查看容器中是否包括某一 Bean 等.
  • HierarchicalBeanFactory : 父子级联IOC容器. 子容器可以通过接口方法访问父容器. 建立起父子层级关联的容器体系, 子容器可以访问父容器的 Bean, 但是父容器不能访问子容器的 Bean. 比如在 SpringMVC 中, 展现层的 Bean 位于一个子容器中, 而业务层和持久层的 Bean 位于父容器中, 这样展现层 Bean 就可以引用业务层和持久层了, 而反过来就不行.
  • ConfigurableBeanFactory : 增强了 IOC 容器的可定制性, 定义了设置类装载器, 属性编辑器以及属性初始化后置处理器.
  • AutowrieCapableBeanFactory : 定义了将容器中的 Bean, 按某种规则, 比如说按名字匹配, 按类型匹配等, 按照这些规则对 Bean 进行自动装配.
  • SingletonBeanRegistry : 允许在运行期间, 向容器注册 Singleton 实例 Bean 的方法.

Spring IOC 中, Bean 默认都是 单例形式 存在的.

ApplicationContext

BeanFactory 的子接口之一.

  • BeanFactory 是 Spring 框架的基础设施, 面向Spring.
  • ApplicationContext面向使用Spring框架的开发者.

ApplicationContext 的功能(继承多个接口)

  • BeanFactory : 能够管理, 装配Bean
  • ResourcePatternResolver : 能够加载资源文件
  • MessageSource : 能够实现国际化等功能
  • ApplicationEventPublisher : 能够注册监听器, 实现监听机制

是应用上下文, 代表着整个容器的所有功能.

AnnotationConfigServletWebServerApplicationContextSpringBoot的默认容器类.

// 返回的就是 ConfigurableApplicationContext
// SpringAppliction.run(xxx.class, args);
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
  return run(new Class<?>[] { primarySource }, args);
}
// 主要逻辑
public ConfigurableApplicationContext run(String... args) {
  StopWatch stopWatch = new StopWatch();
  stopWatch.start();
  ConfigurableApplicationContext context = null;
  Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
  configureHeadlessProperty();
  SpringApplicationRunListeners listeners = getRunListeners(args);
  listeners.starting();
  try {
    ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
    configureIgnoreBeanInfo(environment);
    Banner printedBanner = printBanner(environment);
    // 创建上下文对象
    context = createApplicationContext();
    exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
        new Class[] { ConfigurableApplicationContext.class }, context);
    prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    refreshContext(context);
    afterRefresh(context, applicationArguments);
    stopWatch.stop();
    if (this.logStartupInfo) {
      new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    }
    listeners.started(context);
    callRunners(context, applicationArguments);
  }
  catch (Throwable ex) {
    handleRunFailure(context, ex, exceptionReporters, listeners);
    throw new IllegalStateException(ex);
  }

  try {
    listeners.running(context);
  }
  catch (Throwable ex) {
    handleRunFailure(context, ex, exceptionReporters, null);
    throw new IllegalStateException(ex);
  }
  return context;
}

public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
    + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
    + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
    + "annotation.AnnotationConfigApplicationContext";

protected ConfigurableApplicationContext createApplicationContext() {
  Class<?> contextClass = this.applicationContextClass;
  if (contextClass == null) {
    try {
      switch (this.webApplicationType) {
      case SERVLET:
        contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
        break;
      case REACTIVE:
        contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
        break;
      default:
        contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
      }
    }
    catch (ClassNotFoundException ex) {
      throw new IllegalStateException(
          "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
    }
  }
  return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

getBean()方法解析

AbstractBeanFactory类中, 最终其实调用的是doGetBean方法。

protected <T> T doGetBean(
    String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
    throws BeansException {
  // 转换 beanName
  String beanName = transformedBeanName(name);
  Object bean;

  // Eagerly check singleton cache for manually registered singletons.
  // 获取是否有手动注册的单例对象
  Object sharedInstance = getSingleton(beanName);
  if (sharedInstance != null && args == null) {
    if (logger.isTraceEnabled()) {
      if (isSingletonCurrentlyInCreation(beanName)) {
        logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
            "' that is not fully initialized yet - a consequence of a circular reference");
      }
      else {
        logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
      }
    }
    // 如果有, 从实例工厂或缓存中获取实例
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
  }

  else {
    // Fail if we're already creating this bean instance:
    // We're assumably within a circular reference.
    if (isPrototypeCurrentlyInCreation(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
    }

    // Check if bean definition exists in this factory.
    // 尝试在父类工厂查找是否存在
    BeanFactory parentBeanFactory = getParentBeanFactory();
    if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
      // Not found -> check parent.
      String nameToLookup = originalBeanName(name);
      if (parentBeanFactory instanceof AbstractBeanFactory) {
        return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
            nameToLookup, requiredType, args, typeCheckOnly);
      }
      else if (args != null) {
        // Delegation to parent with explicit args.
        return (T) parentBeanFactory.getBean(nameToLookup, args);
      }
      else if (requiredType != null) {
        // No args -> delegate to standard getBean method.
        return parentBeanFactory.getBean(nameToLookup, requiredType);
      }
      else {
        return (T) parentBeanFactory.getBean(nameToLookup);
      }
    }

    if (!typeCheckOnly) {
      markBeanAsCreated(beanName);
    }

    try {
      // 获取类的定义 将父类和子类的进行合并
      RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
      checkMergedBeanDefinition(mbd, beanName, args);

      // Guarantee initialization of beans that the current bean depends on.
      String[] dependsOn = mbd.getDependsOn();
      // 如果存在依赖, 先 递归 实现依赖bean, 解决循环依赖问题.
      if (dependsOn != null) {
        for (String dep : dependsOn) {
          if (isDependent(beanName, dep)) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
          }
          registerDependentBean(dep, beanName);
          try {
            getBean(dep);
          }
          catch (NoSuchBeanDefinitionException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
          }
        }
      }

      // Create bean instance.
      // 作用域是否是单例的, 判断之前是否已经创建过了. 有就直接返回, 没有就创建一个
      if (mbd.isSingleton()) {
        sharedInstance = getSingleton(beanName, () -> {
          try {
            return createBean(beanName, mbd, args);
          }
          catch (BeansException ex) {
            // Explicitly remove instance from singleton cache: It might have been put there
            // eagerly by the creation process, to allow for circular reference resolution.
            // Also remove any beans that received a temporary reference to the bean.
            destroySingleton(beanName);
            throw ex;
          }
        });
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
      }

      else if (mbd.isPrototype()) {
        // It's a prototype -> create a new instance.
        Object prototypeInstance = null;
        try {
          beforePrototypeCreation(beanName);
          prototypeInstance = createBean(beanName, mbd, args);
        }
        finally {
          afterPrototypeCreation(beanName);
        }
        bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
      }
      // 如果是其它作用域, web容器还有其它作用域, 像 session, request
      else {
        String scopeName = mbd.getScope();
        if (!StringUtils.hasLength(scopeName)) {
          throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
        }
        Scope scope = this.scopes.get(scopeName);
        if (scope == null) {
          throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
        }
        try {
          Object scopedInstance = scope.get(beanName, () -> {
            beforePrototypeCreation(beanName);
            try {
              return createBean(beanName, mbd, args);
            }
            finally {
              afterPrototypeCreation(beanName);
            }
          });
          bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
        }
        catch (IllegalStateException ex) {
          throw new BeanCreationException(beanName,
              "Scope '" + scopeName + "' is not active for the current thread; consider " +
              "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
              ex);
        }
      }
    }
    catch (BeansException ex) {
      cleanupAfterBeanCreationFailure(beanName);
      throw ex;
    }
  }

  // Check if required type matches the type of the actual bean instance.
  // 检查创建的类型是否符合需要实例的类型
  if (requiredType != null && !requiredType.isInstance(bean)) {
    try {
      T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
      if (convertedBean == null) {
        throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
      return convertedBean;
    }
    catch (TypeMismatchException ex) {
      if (logger.isTraceEnabled()) {
        logger.trace("Failed to convert bean '" + name + "' to required type '" +
            ClassUtils.getQualifiedName(requiredType) + "'", ex);
      }
      throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
    }
  }
  return (T) bean;
}
  1. 转换 beanName
  2. 尝试从缓存中加载实例
  3. 实例化Bean
  4. 检查parentBeanFactory
  5. 初始化依赖的Bean
  6. 创建Bean, 并且再检查一次Bean的类型

评论