Spring源码(一)IoC/DI详解。4w字的详细教程——从初始化容器到实例Bean完成。

一、Spring之IoC原理

1.1 词义辨析

Bean对象的区别:

简单来说就是Bean最大的特性是拥有一套完整的生命周期

  • Bean: 在Spirng中Bean不仅仅是一个对象这么简单,Spring中的Bean具有一套完整的生命周期。如

    @Component class A{
    	@Autowired private B b; // 依赖B
    }
    // ---------
    @Component class B{
      @Autowired private A a; // 依赖A
    }
    

    class A —— new A() —— autowired —— 生命周期处理 —— AOP —— 等等操作 ——发现依赖B —— getBean(B)——new B() —— autowired —— 生命周期处理 —— AOP —— 等等操作 ——发现依赖A —— 循环依赖……

  • 对象:只要new出来就好了。就行上面的例子,A a = new A();完全没问题,但是A对象中的属性b是没有值的。

1.2 Spring初始化Bean的过程

1.2.1 入口——构造函数

Spring中管理 注解Bean定义 的容器有两个:AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext。这两个类时专门处理Spring注解方式配置的容器,直接依赖于将注解作为容器配置信息来源的IoC容器。而后者是前者的Web版本,两者的用法及对注解的处理方式几乎没有差别。

AnnotationConfigApplicationContext为例,在初始化atx容器的时候,传入一个参数AppConfig

AnnotationConfigApplicationContext atx = new AnnotationConfigApplicationContext(AppConfig.class);
  • AppConfig.java

      @Configuration("abc")
      @ComponentScan("com.abc")
      @Scope("singleton")
      public class AppConfig {
      	private int a;
      	public AppConfig() {
      		System.out.println("com.abc.AppConfig");
      	}
      }
    

    new AnnotationConfigApplicationContext的时候,来追踪一下构造方法。

    // 最常用的构造函数
    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
      // 实例化了一个DefaultListableBeanFactory
      this();
      // AppConfig是没有Component注解的。但它被扫描是必要的。
      // 将AppConfig这个类注册成一个BeanDefinition添加到Map中
      register(componentClasses);
      // refresh是SpringFramework中最重要的方法,没有之一
      refresh();
    }
    

1.2.2 向容器中注册——Register

在构造方法中调用了三个方法,this,register,refresh。其中初始化IoC容器atx的是register方法

  • register方法

    // 注册一个注解Bean
    // 新注册的注解Bean必须手动调用refresh方法,来刷新容器对Bean的处理。
    @Override
    public void register(Class<?>... componentClasses) {
      this.reader.register(componentClasses);
    }
    
  • 继续调用readerregister方法,其中reader是一个bean定义读取器 AnnotatedBeanDefinitionReader

    // 注册多个{注解Bean定义}类
    public void register(Class<?>... componentClasses) {
    	for (Class<?> componentClass : componentClasses) {
    		registerBean(componentClass);
    	}
    }
    
  • 继续调用registerBean方法来注册指定的类

    // 注册一个{注解Bean定义}类
    public void registerBean(Class<?> beanClass) {
      doRegisterBean(beanClass, null, null, null);
    }
    
  • 继续调用doRegisterBean方法来注册一个指定的类

    <T> void doRegisterBean(Class<T> beanClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
    			@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
      // 注解生成bean定义
      // 根据指定的注解类,创建一个数据结构——封装注解bean定义的数据结构
      AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
      if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
        return;
      }
    
      // 设置实例提供者
      abd.setInstanceSupplier(instanceSupplier);
    
      // 1. 解析bean作用域
      // 获取 Scope注解元数据 对象
      // 解析bean的作用域
      // prototype为原型模式,singleton为单例
      ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
      // 设置注解bean定义的作用域
      abd.setScope(scopeMetadata.getScopeName());
      // 获取beanName ,如果name没有传值就从beanNameGenerator生成一个
      String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
      // 2. 处理通用注解
      // 处理注解bean定义中的通用注解(如:@Lazy @Primary等)
      AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
      if (qualifiers != null) {
        for (Class<? extends Annotation> qualifier : qualifiers) {
          if (Primary.class == qualifier) {
            abd.setPrimary(true);
          }
          else if (Lazy.class == qualifier) {
            abd.setLazyInit(true);
          }
          else {
            abd.addQualifier(new AutowireCandidateQualifier(qualifier));
          }
        }
      }
      for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
        customizer.customize(abd);
      }
    
      // 创建一个指定bean名称的Bean定义对象。封装  注解bean定义数据
      BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
      // 3. 创建作用域的代理对象
      definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
      // 4. 通过BeanDefinitionReaderUtils向容器注册bean
      BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }
    

    可以看到doRegisterBean注册Bean分为4步:

    • 1 、解析bean作用域,是通过这个方法resolveScopeMetadata来解析的。

    • 2 、处理通用注解,如Primary,Qualifer等注解。

    • 3 、创建作用域的代理对象

    • 4 、通过BeanDefinitionReaderUtils向容器注册bean最终会看到 this.beanDefinitionMap.put(beanName, beanDefinition); 这样的一句话,意思就是放入容器中一个Bean定义。


    • 先来进行第一步:

    • 第一步: AnnotationScopeMetadataResolver#resolveScopeMetadata解析bean的作用域。

      public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
        ScopeMetadata metadata = new ScopeMetadata();
        if (definition instanceof AnnotatedBeanDefinition) {
          // 获取Bean定义,强转为子类型,注解Bean定义
          AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
          // AnnotationAttributes这个类继承自LinkedHashMap
          // annDef.getMetadata();会查询出bean中所有的注解放在一个数组中。StarandAnnoationMetadata
          AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
            annDef.getMetadata(), this.scopeAnnotationType);
          // 获取所有Scope注解的值设置到要返回的对象中。
          if (attributes != null) {
            metadata.setScopeName(attributes.getString("value"));
            // 获取Scope注解中proxyMode的值,在创建代理对象的时候会用到。
            ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
            // 如果proxyMode的值为NO 或者 DEFAULT
            if (proxyMode == ScopedProxyMode.DEFAULT) {
              // 则设置成默认的代理
              proxyMode = this.defaultProxyMode;
            }
            // 为返回的元数据设置proxyMode
            metadata.setScopedProxyMode(proxyMode);
          }
        }
        // 返回解析的作用域元信息对象
        return metadata;
      }
      
    • 第二步:处理通用注解==@Lazy,@DependsOn,@Role,@Description== 由这个方法AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);调用:

      static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
        AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
        if (lazy != null) {
          abd.setLazyInit(lazy.getBoolean("value"));
        }
        else if (abd.getMetadata() != metadata) {
          lazy = attributesFor(abd.getMetadata(), Lazy.class);
          if (lazy != null) {
            abd.setLazyInit(lazy.getBoolean("value"));
          }
        }
      
        if (metadata.isAnnotated(Primary.class.getName())) {
          abd.setPrimary(true);
        }
        AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
        if (dependsOn != null) {
          abd.setDependsOn(dependsOn.getStringArray("value"));
        }
      
        AnnotationAttributes role = attributesFor(metadata, Role.class);
        if (role != null) {
          abd.setRole(role.getNumber("value").intValue());
        }
        AnnotationAttributes description = attributesFor(metadata, Description.class);
        if (description != null) {
          abd.setDescription(description.getString("value"));
        }
      }
      
    • 第三步:根据Bean定义 类中配置的作用域为其应用相应的代理策略

      static BeanDefinitionHolder applyScopedProxyMode(
        ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
        ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
        // 如果为NO,则不设置代理对象。
        if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
          return definition;
        }
        // 获取配置的@Scope注解中的proxyMode值,如果为TARGET_CLASS返回true,如果为INTERFACE返回false
        boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
        return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
      }
      
    • 第四步:通过BeanDefinitionReaderUtils向容器注册bean

      public static void registerBeanDefinition(
        BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
        throws BeanDefinitionStoreException {
        // 向容器中注册Bean定义
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
      
        // 如果存在别名,注册别名
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
          for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
          }
        }
      }
      
      • 在第四步中,可以看到调用 registerBeanDefinition 方法向容器注入了Bean定义。这个方法是DefaultListableBeanFactory实现的。这是默认的列表Bean工厂,向工厂注册,也就是把原材料(BeanDefinition)提供给工厂。

        public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
              			throws BeanDefinitionStoreException {
                // 如果是抽象BeanDefin
                if (beanDefinition instanceof AbstractBeanDefinition) {
                  try {
                    // 尝试验证Bean定义
                    ((AbstractBeanDefinition) beanDefinition).validate();
                  } catch (BeanDefinitionValidationException ex) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                                           "Validation of bean definition failed", ex);
                  }
                }
              
                // 从Bean工厂的beanDefinitionMap中获取指定名称的Bean定义
                BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
                // 第一次肯定获取不到。
                // 如果获取到Bean定义
                if (existingDefinition != null) {
                  // ...省略不重要的代码
                  // 放入bean定义
                  this.beanDefinitionMap.put(beanName, beanDefinition);
                }
                // 如果没有获取到Bean定义
                else {
                  // 判断是否开始创建Bean
                  if (hasBeanCreationStarted()) {
                    // Cannot modify startup-time collection elements anymore (for stable iteration)
                    synchronized (this.beanDefinitionMap) {
                      // 把Bean定义放入工厂容器中
                      this.beanDefinitionMap.put(beanName, beanDefinition);
                      List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                      updatedDefinitions.addAll(this.beanDefinitionNames);
                      updatedDefinitions.add(beanName);
                      this.beanDefinitionNames = updatedDefinitions;
                      removeManualSingletonName(beanName);
                    }
                  }
                  // 如果没有正在创建
                  else {
                    // Still in startup registration phase
                    // 直接放入工程容器中
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    // 添加BeanName
                    this.beanDefinitionNames.add(beanName);
                    // 删除单例名称
                    removeManualSingletonName(beanName);
                  }
                  this.frozenBeanDefinitionNames = null;
                }
              
                if (existingDefinition != null || containsSingleton(beanName)) {
                  resetBeanDefinition(beanName);
                }
              }
        

至此SpringBean就已经全部注册完成了。在这里需要理解注册这个词,注册到容器中就是把bean定义放到容器中。

  • bean定义就是原材料——bean的属性,属性名,方法名称,方法参数,是否有父类,是否是抽象等等。
  • 容器就是工厂。工厂有了原材料BeanDefinition即Bean定义才能生产对象。

1.2.3 初始化Bean——Refresh

(一)有待研究的方法 | 可跳过

  • org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance 从Bean实例中获取对象
  • org.springframework.beans.factory.support.AbstractBeanFactory#initBeanWrapper 初始化BeanWrapper
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyPropertyValues在给属性赋值的之后没有属性…

(二)获取单例是怎么一回事?

在register方法执行完之后,只是将Bean定义即BeanDefinition放入到了容器中。接下来,执行refresh方法刷新容器,会将Bean定义中一些原始类实例化。然后查看register注解的用户的类上是否有 @ComponentScan注解,读取包下的Bean定义加入到容器中。然后对 lazy-init=false的bean进行实例化。自动注入

(三)refresh源码剖析

  • 从断点可以看出:在执行完register方法之后,执行refresh之前,就已经存在了五个开天辟地的 BeanDefinition和自己在启动容器atx时传入的配置类AppConfig(名字自己起的abc,自己随便起就好)。

    image-20200306175722691
  • 而在refresh方法中,执行了许多过程。refresh源码如下:

    @Override
    public void refresh() throws BeansException, IllegalStateException {
      synchronized (this.startupShutdownMonitor) {
        // 1.调用容器准备刷新的方法,获取容器当前时间,同时给容器设置同步标识
        prepareRefresh();
        // Tell the subclass to refresh the internal bean factory.
        // 2. 告诉子类刷新内部bean工厂
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // Prepare the bean factory for use in this context.
        // 3. 准备bean工厂以供在此上下文中使用
        prepareBeanFactory(beanFactory);
        try {
          // Allows post-processing of the bean factory in context subclasses.
          // 4. 允许在上下文子类中对bean工厂进行后处理。
          postProcessBeanFactory(beanFactory);
    
          // 5. 调用了getBean方法,也就是初始化实例对象。
          // 重要的方法
          // 在spring的环境中区执行已经被注册的factory processors
          // 设置执行自定义的ProcessBeanFactory和spring自己定义的
          // Invoke factory processors registered as beans in the context.
          invokeBeanFactoryPostProcessors(beanFactory);
    
          // Register bean processors that intercept bean creation.
          // 6. 注册拦截bean创建的bean处理器。
          registerBeanPostProcessors(beanFactory);
    
          // 7Initialize message source for this context.
          // 初始化此上下文的消息源。
          initMessageSource();
    
          // 8. 初始化事件广播器
          // Initialize event multicaster for this context.
          initApplicationEventMulticaster();
    
          // 9. Initialize other special beans in specific context subclasses.
          // 初始化特定上下文子类中的其他特殊bean。
          onRefresh();
    
          // Check for listener beans and register them.
          // 10. 检查侦听器bean并注册它们。
          registerListeners();
    
          // new 对象。被扫描的对象会被实例化。可调用构造方法证明
          // Instantiate all remaining (non-lazy-init) singletons.
          // 11* 实例化所有剩余的(非延迟初始化)单例。
          finishBeanFactoryInitialization(beanFactory);
    
          // Last step: publish corresponding event.
          // 12. 最后一步:发布对应的事件。
          finishRefresh();
          .....省略不重要方法。
        }
      }
    }
    

    ​ 把refresh的方法分为12个过程。其中主要关注 11----finishBeanFactoryInitialization这个方法。因为在这里实例化了所有的对象放入对象池中。


    ​ 在执行完5---invokeBeanFactoryPostProcessors这个方法后(如下有调试截图),可以看到在配置路径下的类被扫描了。并且将Bean定义放入到了容器中。同时还调用了 getBean方法。实例化了一些后置处理器、监听器、环境、等一些原始类。供框架使用。同时,也扫描了配置路径下的类。将Bean定义放入容器中——第二张图可证明。

    image-20200306181421716 image-20200306180805431
  • 执行 6、7、8、10这几个步骤时 还实例化了几个框架级别的类放到了单例池 singletonObjects 中。现在来看 10--finishBeanFactoryInitialization方法。

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
      // 这是Spring3提供的一个方法,为容器指定一个转换服务,在对某些bean属性进行转换时使用
      if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
          beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
          beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
      }
      // 如果此时没有bean后置处理器注册任何been(例如PropertyPlaceholderConfigurer bean
      // 则注册默认的嵌入式值解析器,主要是为了在注释属性值中进行解析。
      if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
      }
      String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
      for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
      }
    
      // 为了类型匹配,停止使用临时的类加载器。
      // Stop using the temporary ClassLoader for type matching.
      beanFactory.setTempClassLoader(null);
    
      //缓存容器中所有注册的BeanDefinition元数据,以防被修改。
      beanFactory.freezeConfiguration();
    
      // 实例化所有的单例对象
      // 对配置了lazy = false的对象进行实例化。
      beanFactory.preInstantiateSingletons();
    }
    

    在这个方法中概括性的将就一句话:执行了 beanFactory.preInstantiateSingletons();这条语句。

    作用:将配扫描到的lazy=false(默认为false)的bean定义实例化。

  • 来看preInstantiateSingletons方法:省略了日志打印代码

    public void preInstantiateSingletons() throws BeansException {
      // 省略了日志打印代码
      // 获得所有bean的名字
      // 里面的名字都是可能要去实例化的class
      // 为什么是可能呢。1. lazy=true 2.bean本身定义错误..等等,所以是可能
      List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    
      // Trigger initialization of all non-lazy singleton beans...
      for (String beanName : beanNames) {
        // 获取指定名称的Bean定义
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        // bean不是抽象的,并且是单例的,并且不是懒加载
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
          // 如果是工厂bean,也就是FactoryBean
          if (isFactoryBean(beanName)) {// 这里面的先不理解}
          // 如果是普通Bean
          else {
            // 获取一下bean,确认bean是否存在,如果存在就不再创建实例,如果不存在程序才继续执行。
            // DI的核心方法!!!!!!!!
            getBean(beanName);
          }
        }
      }
    }
    
    image-20200306183438639

    只研究自己的 BeanDefinition是如何被实例化的。也就是abc和cityService。在preInstantiateSingletons方法中,先做了一些判断,然后调用getBean进行实例化.

  • 接着看 getBean方法,getBean本身只是一个壳,它调用了doGetBean方法,doGetBean才是主角。来看doGetBean源码

    @Override
    public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
    }
    

    doGetBean

    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
    							  @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
      // 根据指定名称获取被管理的bean的名称,剥离指定名称对容器的相关依赖
      // 如果指定的是别名,将别名转换为规范的bean名称。
      // step1. 获取单例对象
      final String beanName = transformedBeanName(name);
      // 该方法的返回值。
      Object bean;
    
      // 经典方法getSingleton
      // 从缓存中读取看是否已经有被创建过得单例模式的Bean
      // 对于单例模式的Bean,整个IoC容器只创建一次。不需要重复创建。
      Object sharedInstance = getSingleton(beanName);
      if (sharedInstance != null && args == null) {
        // 获取指定的Bean的实例对象,主要完成FactoryBean的相关处理
        // 注意:FactoryBean是创建对象。BeanFactory管理对象。两者的区别
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
      }
      // 缓存中没有正在创建的单例Bean
      else {
        // step2. 检查循环依赖
        // 循环依赖
        // 缓存中已有原型模式的bean,但是由于循环引用,导致实例化对象失败.
        if (isPrototypeCurrentlyInCreation(beanName)) {
          throw new BeanCurrentlyInCreationException(beanName);
        }
    
        // 在IoC容器中查找是否存在指定名称的BeanDefinition。
        // 首先检查是否能在当前的BeanFactory中获取所需要的Bean,
        // 如果不能,则委托当前容器的父容器去查找,还是找不到继续沿着容器的继承体系一直查找。
        // 3. 获取BeanDefinition
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
          // Not found -> check parent.
          // 解析指定Bean名称的原始名称
          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);
          }
        }
    
        // step4. 标记Bean被创建
        // 创建的Bean是否需要类型验证,一般不需要
        // 向容器标记bean正在创建过程中
        if (!typeCheckOnly) {
          markBeanAsCreated(beanName);
        }
    
        try {
          // 根据指定Bean名称获取其父级的bean定义
          // 主要解决bean继承时子类和父类的公共问题所在
          // step5. 合并bean定义
          final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
          checkMergedBeanDefinition(mbd, beanName, args);
    
          // 获取当前Bean所有依赖bean的名称
          // step6. 获取@DependsOn注解。检查是否有依赖其他Bean
          String[] dependsOn = mbd.getDependsOn();
          // 如果当前Bean有依赖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 + "'");
              }
              // 把被依赖的bean注册给当前bean
              registerDependentBean(dep, beanName);
              try {
                // 递归调用getBean()方法,获取依赖Bean的依赖Bean
                getBean(dep);
              } catch (NoSuchBeanDefinitionException ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
              }
            }
          }
    
          // 7. 根据作用域和BeanDefinition创建实例对象。
          if (mbd.isSingleton()) {
            // 这里使用匿名内部类创建的Bean实例对象,并且注册给当所依赖的对象
            sharedInstance = getSingleton(beanName, () -> {
              try {
                // 7.1 重中之重!!!!!!!
                // 创建一个指定的Bean实例对象,如果有父级继承,则合并当前子类和父类的定义
                return createBean(beanName, mbd, args);
              } catch (BeansException ex) {...省略异常信息...}
            });
            // 获取给定的实例Bean对象,单例的。 // 上面已经得到bean了,为什么还要再获取一次呢?是为了判断获取的是普通Bean还是工厂Bean产生的Bean
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
          }
          // 如果是原型模式,每次都创建一个新对象。
          else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
              // 回调beforePrototypeCreation方法,默认的功能室注册当前创建的原型对象。
              beforePrototypeCreation(beanName);
              // 创建指定的Bean对象的实例
              prototypeInstance = createBean(beanName, mbd, args);
            } finally {
              // 回调afterPrototypeCreation方法,默认的功能是告诉IoC容器不再创建指定的Bean的原型对象
              afterPrototypeCreation(beanName);
            }
            // 获取给定的实例Bean对象
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
          }
          // 如果bean既不是单例的也不是原型的
          // 则根据bean定义资源中配置的声明周期返回,选择实例化bean的合适方法,
          // 这种方式在Web中比较常用,如:request、session、application
          else {....这里不重要。先理解别的代码.... }
        } catch (BeansException ex) {}
      }
    
      // 对创建的bean实例对象进行类型检查
      if (requiredType != null && !requiredType.isInstance(bean)) {....这里不重要。先理解别的代码....}
      return (T) bean;
    }
    

    代码过多,来理解一下流程,根据``doGetBean`的源码,结为以下7步:其中第七步才是真的创建Bean

    1. 从单例池中获取单例对象,(第一次肯定不存在嘛,Spring正在创建这个对象,单例池里是没有的。所以获取不到。)

    2. 检查循环依赖

    3. 从当前容器中获取BeanDefinition重点:在Spring中Bean是产品,BeanDefinition是原料,只有获取了原料才能生产产品,如果当前容器获取不到,就沿着容器的继承体系向上递归查找。

    4. 标记Bean已经被创建

    5. 合并Bean定义

    6. 获取@DependsOn注解。检查是否有依赖其他Bean

    7. 根据作用域和BeanDefinition创建实例对象。

      • 单例——创建单例Bean

      • 原型——创建原型Bean

      • session、request、application——一般web中用

    8. 返回Bean

    doGetBean 方法中真正创建Bean的过程是在第七步中的 7.1 ---- createBean这条语句。注意,createBean是在一个lambda表达式中。createBean这个方法是作为匿名内部类的方式被 getSingleton调用的。先记住createBean这个方法,它会被调用,但调用的地方并不是当前方法。而是 getSingleton

  • 来看一下getSingleton到底有什么神奇的地方。

    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
      // step1. 加锁
      synchronized (this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
          if (this.singletonsCurrentlyInDestruction) {
            throw new 异常信息省略// 循环注入
          }
          // step2. 创建对象之前先给对象标注一下状态,表示bean正在创建
          beforeSingletonCreation(beanName);
          boolean newSingleton = false;
          boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
          if (recordSuppressedExceptions) {
            this.suppressedExceptions = new LinkedHashSet<>();
          }
          try {
            // step3. 通过这句代码来创建单例对象,但是singletonFactory其实传进来的是一个lambda表达式。调用这个方法的调用者传递。
            // lambda一般是createBean方法
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
          }
          catch (IllegalStateException ex) {...省略异常信息...}
          catch (BeanCreationException ex) {...省略异常信息...}
          finally {
            if (recordSuppressedExceptions) {
              this.suppressedExceptions = null;
            }
            afterSingletonCreation(beanName);
          }
          if (newSingleton) {
            // step4. 向容器中添加单例对象。!!!!! TODO
            addSingleton(beanName, singletonObject);
          }
        }
        // step5. 返回创建好的Bean
        return singletonObject;
      }
    }
    

    整个getSingleton方法共有5处关键的语句:

    1. 加锁,进入方法的第一步是先给单例池加上锁,保证线程安全。

    2. 标记一下该bean正在被创建。点开这个方法可知通过 !this.singletonsCurrentlyInCreation.add(beanName)这条语句来标记的。singletonsCurrentlyInCreation是一个集合。其中存储了正在被创建的beanName

    3. ==重头戏:==上面说的 createBean方法就是getObject方法来执行的。因为是一个匿名内部类嘛。

      protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      			throws BeanCreationException {
        RootBeanDefinition mbdToUse = mbd;
        // 判断当前创建的Bean是否可以实例化,即是否能通过当前类加载器加载。
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
          mbdToUse = new RootBeanDefinition(mbd);
          mbdToUse.setBeanClass(resolvedClass);
        }
      
        try {
          // 校验和准备bean中的方法覆盖。
          mbdToUse.prepareMethodOverrides();
        } catch (BeanDefinitionValidationException ex) {...省略异常信息...}
      
        try {
          // 如果配置了bean初始化前和初始化后的处理器,则试图返回一个需要创建bean的代理对象。
          Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
          if (bean != null) {
            return bean;
          }
        } catch (Throwable ex) {...省略异常信息...}
      
        try {
          // 创建Bean的入口
          Object beanInstance = doCreateBean(beanName, mbdToUse, args);
          if (logger.isTraceEnabled()) {
            logger.trace("Finished creating instance of bean '" + beanName + "'");
          }
          return beanInstance;
        } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {...省略异常信息...
                                                                                  } catch (Throwable ex) {...省略异常信息...}
      }
      

      createBean只做了一些基本逻辑依旧要委托给doCreateBean方法来创建实例。

      来看doCreateBean源码

      protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      			throws BeanCreationException {
      		// 封装被创建的Bean对象
        BeanWrapper instanceWrapper = null;
      
        if (mbd.isSingleton()) { // 如果是单例的,就要从缓存池中移除原有的对象
          instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
          // step1. 生成Java对象,注意只是创建了Java对象,但不能称之为bean因为还没有依赖注入等生命周期
          instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        // 获取实例化对象的类型
        final Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
          mbd.resolvedTargetType = beanType;
        }
      
        // 调用postProcess后置处理提
        synchronized (mbd.postProcessingLock) {...省略,自己研究...}
      
        // 向容器中缓存单例模式的Bean对象,防止循环引用。
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                          isSingletonCurrentlyInCreation(beanName));
        // 这是一个匿名内部类,为了防止循环引用,尽早持有对象的引用。
        if (earlySingletonExposure) {...省略,自己研究...}
      
        // bean 对象的初始化,依赖注入在此生效。
        // 这个exposedObject对象在初始化完成之后,返回依赖注入完成后的bean
        Object exposedObject = bean;
        try {
          // 将bean实例对象封装,并且将bean定义中配置的属性值赋给实例对象。
          // 英文单词:populate迁移,填充数据的意思
          // step2. 具体依赖注入实现二
          // 注入Bean所包含的Java对象
          populateBean(beanName, mbd, instanceWrapper);
          // 初始化bean对象 初始化给定的bean实例,应用工厂回调以及init方法和bean后处理器。对于传统定义的bean,从{createBean}调用,对于现有bean实例,从{initializeBean}调用。
          exposedObject = initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable ex) {...省略异常信息...}
        if (earlySingletonExposure) {...省略,自己研究...
          // 获取指定名称已经注册的单例模式的Bean对象
          // 根据名称获取的已经注册的bean和正在实例化的bean 是同一个
          // 当前实例化的bean初始化完成
          // 当前bean依赖其他bean,并且当发生循环引用时不允许创建新的实例对象
          // 获取bean所依赖的其他bean
          // 对依赖的其他bean进行类型检查
                                    }
        // step3. 返回bean!
        return exposedObject;
      }
      

      这里又分为两步:

      1. 生成Java对象,注意只是创建了Java对象,但不能称之为bean因为还没有依赖注入等生命周期

        protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
          ...不看一眼望不到头的代码了...
            // 调用默认无参构造方法来创建Java对象
            return instantiateBean(beanName, mbd);
        }
        

        来看instantiateBean方法,

        protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
        	...不看一眼望不到头的代码了...
          Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
          BeanWrapper bw = new BeanWrapperImpl(beanInstance);
          return bw;	
        }
        

        instantiateBean方法中调用了instantiate来实例化对象(注意这个单词和初始化的区别)

        public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
          // 如果没有覆盖方法,就不需要CGLIB父类的方法。
          if (!bd.hasMethodOverrides()) {
            // 通过JDK反射机制来创建对象
            // 使用工具类BeanUtils来实例化bean,通过反射机制调用"构造方法.newInstance(args)"来进行实例化。
            return BeanUtils.instantiateClass(constructorToUse);
          }
          else {
            // 使用CGLIB来实例化对象
            return instantiateWithMethodInjection(bd, beanName, owner);
          }
        }
        

        点进去instantiateClass 方法还可以往下看到 return ctor.newInstance(args));这样的源码通过JDK反射来new对象。至此!!!终于!!对象创建好了。但只是一个Java对象,并不是Spring的Bean。想要创建Bean还差一步——依赖注入。

      2. 依赖注入,给bean注入属性。来看populateBean注入bean的源码

        protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        	...只看核心代码吧...
          // 获取容器在解析Bean定义时,BeanDefinition中的属性
          PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
          boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
          
          if (needsDepCheck) {
            // 检查依赖
            checkDependencies(beanName, mbd, filteredPds, pvs);
          }
        
          if (pvs != null) {
            // 对属性进行注入
            applyPropertyValues(beanName, mbd, bw, pvs);
          }
        }
        

        其中这个方法中判断了很多关于BeanDefinition的属性东西。业务逻辑暂时抛开,最后一句 applyPropertyValues 是对属性的依赖注入。然后在该方法又进行了一堆判断。调用了 BeanWrapper.setPropertyValues方法来注入属性的。具体源码就不看了。有兴趣自己研究。

    4. 向单例池中添加创建好的单例对象,通过addSingleton方法向单例池中添加创建好的单例对象this.singletonObjects.put(beanName, singletonObject);

      protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
          this.singletonObjects.put(beanName, singletonObject);
          this.singletonFactories.remove(beanName);
          this.earlySingletonObjects.remove(beanName);
          this.registeredSingletons.add(beanName);
        }
      }
      
    5. 返回该单例对象

  • 至此doGetBean就完成了


总结一下流程是这样的:时序图是最简单的

在这里插入图片描述

1.3 BeanPostProcessor后置处理器

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation

词义辨析:初始化、实例化

  • 实例化:是指对象已经创建好放在内存之中。

  • 初始化:初始化可以理解为,将对象装载进虚拟机中,然后对对象的属性赋值、执行静态代码快等操作。

      postProcessBeforeInstantiation	// 初始化,BeanPostProcessor插手初始化的过程
      postProcessBeforeInitialization // 实例化,InstantiationAwareBeanPostProcessor插手实例化的过程
    

    后置处理器拦截bean生命周期

A —— new —— xxxBeanPostProcessor —— A() —— lifeCiclyCallBack|@PostConstruct—— 自动注入AutowiredAnnotationBeanPostProcessor —— BeanFactoryProcessor

1.4 BeanDefinition详解

BeanDefinition描述一个bean实例,该实例具有属性值、构造函数参数值和具体实现提供的进一步信息。

1.4.1 继承体系一览

BeanDefinition继承体系

image-20200305152301264

其中RootBeanDefinition最为常见

1.4.2 BeanDefinition接口的内容

// 定义两个常量
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;// 原型作用域 singleton
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;// 原型作用域 prototype

// 获得Bean定义的一些名字:父类名字,bean全名,工厂bean的名称,工厂方法的名称,初始化方法的名称,销毁方法的名称
parentName: String
beanClassName: String
factoryBeanName: String
factoryMethodName: String
initMethodName: String
destroyMethodName: String
// 获取Bean的一些注解:作用域,懒加载,依赖
scope: String
lazyInit: boolean
dependsOn: String...
dependsOn: String[]
// 获取Bean的一些状态:是否单例,是否首先,是否原型,是否抽象,是否自动注入候选
isAutowireCandidate: boolean
isPrimary: boolean
isSingleton: boolean
isPrototype: boolean
isAbstract: boolean
// 获取Bean的一些内容:属性值,构造参数的集合,资源描述,原生的BeanDefinition
constructorArgumentValues: ConstructorArgumentValues
propertyValues: MutablePropertyValues
resourceDescription: String
originatingBeanDefinition: BeanDefinition

1.4.3 AbstractBeanDefinition抽象类

AbstractBeanDefinition是一个抽象类,继承自BeanDefinition。BeanDefinition主要定义了很多对Bean定义的方法。AbstractBeanDefinition抽象类基本实现了getter和setter。并且添加了自动类型匹配规则——匹配规则定义了五种,有一种过时了。AbstractBeanDefinition还添加了beanClass这个方法的判断逻辑。就是Bean的Class类型。具体添加的内容如下:

  • 添加的常量如下:

    public static final String SCOPE_DEFAULT = "";
    public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
    public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
    public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
    public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
    @Deprecated
    public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
    public static final int DEPENDENCY_CHECK_NONE = 0;
    public static final int DEPENDENCY_CHECK_OBJECTS = 1;
    public static final int DEPENDENCY_CHECK_SIMPLE = 2;
    public static final int DEPENDENCY_CHECK_ALL = 3;
    public static final String INFER_METHOD = "(inferred)";
    
  • resolveBeanClass 解析bean是否有Class,能否被加载

  • hasBeanClass getBeanClass setBeanClass 有关bean的Class的处理逻辑

  • public void applyDefaults(BeanDefinitionDefaults defaults) 应用默认的BeanDefinition

  • public void overrideFrom(BeanDefinition other) 用其他的BeanDefinition覆盖

  • public void setAbstract(boolean abstractFlag) 添加抽象的相关处理

  • setAutowireMode getAutowireMode 添加自动注入类型的相关处理

  • getResolvedAutowireMode

  • setDependencyCheck getDependencyCheck 检查依赖检查的相关处理

  • addQualifier hasQualifier getQualifier getQualifiers添加qulifier的相关处理

  • setPropertyValues hasPropertyValues 添加Bean属性的相关处理

  • getMethodOverrides hasMethodOverrides添加Bean方法覆盖的相关处理

  • setInitMethodName setEnforceInitMethod setDestroyMethodName setEnforceDestroyMethod 添加初始化方法,销毁方法的相关处理

  • setSynthetic isSynthetic 添加合成Bean的相关处理

  • setResource

  • validate 验证相关方法

  • prepareMethodOverrides 预处理方法覆盖

1.4.4 RootBeanDefinition类

根bean定义表示在运行时支持Spring BeanFactory中的特定bean的合并bean定义。它可能是从相互继承的多个原始bean定义创建的,通常注册为{@link GenericBeanDefinition GenericBeanDefinitions}。根bean定义本质上是运行时的“统一”bean定义视图。根bean定义也可用于在配置阶段注册单个bean定义。但是,***自Spring2.5以来***,以编程方式注册bean定义的首选方法是{@link GenericBeanDefinition}类。GenericBeanDefinition的优点是它允许动态定义父依赖项,而不是将角色“硬编码”为根bean定义。

RootBeanDefinition继承自AbstractBeanDefinition,在父类的基础上最重要的是扩展了Bean定义的内容 解析Bean的类型工厂方法

  • BeanDefinitionHolder添加BeanDefinitionHolder相关处理
  • 添加是否能缓存
  • 添加工厂bean方法是否唯一
  • 添加处理ConstructorArguments的方法

1.5 Spring循环依赖

  • Spring中只有单例对象支持循环依赖,如果是原型对象就不支持了。

  • 1.0的例子中,在getBean(A)的时候,会给A附上一个状态标注A正在创建中,这样,在初始化A的过程中去循环依赖B,在创建B的过程中会发现A正在创建中,而此时A就是一个对象(没有赋值属性b的对象)。解决循环依赖

  • 源码解释:markBeanAsCreated方法用来标识Bean正在创建中。由AbstractBeanFactory的属性alreadyCreated来标识。全文一共3处调用了markBeanAsCreated方法。分别是doGetBean,configureBean,applyBeanPropertyValues,后两个正好发生在依赖注入上。

protected void markBeanAsCreated(String beanName) {
    if (!this.alreadyCreated.contains(beanName)) {
      synchronized (this.mergedBeanDefinitions) {
        if (!this.alreadyCreated.contains(beanName)) {
          // Let the bean definition get re-merged now that we're actually creating
          // the bean... just in case some of its metadata changed in the meantime.
          clearMergedBeanDefinition(beanName);
          this.alreadyCreated.add(beanName);
        }
      }
    }
  }
  1. getBean方法中调用doGetBean

    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
    							  @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    	....
      	// 创建单例模式的Bean实例对象。
        // Create bean instance.
        if (mbd.isSingleton()) {
          // 这里使用匿名内部类创建的Bean实例对象,并且注册给当所依赖的对象
          sharedInstance = getSingleton(beanName, () -> {
          try {
              // 创建一个指定的Bean实例对象,如果有父级继承,则合并当前子类和父类的定义
            return createBean(beanName, mbd, args);
            } catch (BeansException ex) {
            // 显式的从容器中单例模式的Bean缓存中清除实例对象
              destroySingleton(beanName);
              throw ex;
            }
          });
          // 获取给定的实例Bean对象,单例的。
          bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
      ....
    }
    
  2. doGetBean调用getSingleton

    并且传递过来一个参数singletonFactory,这是上面doGetBean传过来的一个lambda表达式。真正创建Bean就是在回调方法CreateBean里执行的。

    @Nullable public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
      Object singletonObject = this.singletonObjects.get(beanName);
      ......  
        // 创建对象之前先给对象标注一下状态,表示bean正在创建
      beforeSingletonCreation(beanName);
        boolean newSingleton = false;
      boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
        if (recordSuppressedExceptions) {
          this.suppressedExceptions = new LinkedHashSet<>();
        }
        try {
          // 通过这句代码来创建单例对象,但是singletonFactory其实传进来的是一个lambda表达式。调用这个方法的调用者传递。
          // lambda一般是createBean方法
          singletonObject = singletonFactory.getObject();
          newSingleton = true;
        }
      .......
    }
    
  3. getSingleton请注意beforeSingletonCreation这个方法。这个方法里往singletonsCurrentlyInCreation这个Set集合中添加了当前正在实例化的Bean名称,标识当前bean的状态

    private final Set<String> singletonsCurrentlyInCreation =
    			Collections.newSetFromMap(new ConcurrentHashMap<>(16));
    
    protected void beforeSingletonCreation(String beanName) {
      if (!this.inCreationCheckExclusions.contains(beanName) && 
          //给bean标明正在创建bean。
          !this.singletonsCurrentlyInCreation.add(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
      }
    }
    

二、Spring知识

1.1 Spring常用注解

1.1.1 骨灰级别

@Service@Controller@RequestMapping@Component@Mapper@Autowired

1.1.2 一般级别

@GetMapping… @Qualifier @Lazy @Primary @RequestParam

ComponentScan 指定的包会被Spring扫描,进行初始化Bean对象

@Qualifier A,B都实现了C,向D类注入C的时候有两个选择,可以使用@Qualifier注入指定名称的类

@Primary A,B都实现了C,向D类注入C的时候有两个选择,优先选择被@Primary标注的类

@RequestBody post请求接收参数

@ReponseBody 响应参数为Json格式

@Scope 作用域单例还是原型

@DeleteMapping

@PutMapping 新增数据

@PatchMapping put请求的补充,局部更新,只能算是一个标准,和put没什么分别

@Configuration 和Service等注解一样,源码里指定了别名为Component

1.1.3 少见注解

@PostConstruct @PreDestory

@Value 用来给属性注入Pperties

我罕见的

  1. @Role 标识Bean的类别

    • ROLE_APPLICATION = 0
      • bean的默认角色
      • 标识应用的主要的主要角色
      • 通常对应于用户定义的bean
    • ROLE_SUPPORT = 1
      • 标识较大配置的一部分
      • 通常是仔细观察特定的ComponentDefinition时重要的提示,而不是体现在应用
    • ROLE_INFRASTRUCTURE = 2
      • 标识后台角色,与最终用户无关
      • 通常供是内部工作的bean使用
  2. @Description 描述方法或者类

  3. @Cacheable 可缓存

  4. @AliasFor 在Spring的众多注解中,经常会发现很多注解的不同属性起着相同的作用,比如@RequestMapping的value属性和path属性,这就需要做一些基本的限制,比如value和path的值不能冲突,比如任意设置value或者设置path属性的值,都能够通过另一个属性来获取值等等。为了统一处理这些情况,Spring创建了@AliasFor标签。

  5. @Import 在应用中,有时没有把某个类注入到IOC容器中,但在运用的时候需要获取该类对应的bean,此时就需要用到@Import注解。

    示例:没有疤Cat类和Dog类交给Spring管理,但是又要从容器中获取Dog类和Cat类。

    class Cat(){}
    class Dog(){}
    
    @SpringBootApplication
    @ComponentScan
    // 把用到的资源导入到当前容器中
    @Import({Dog.class, Cat.class})
    class App(){
      public static void main(String[] args) throws Exception {
            ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
            System.out.println(context.getBean(Dog.class));
            System.out.println(context.getBean(Cat.class));
            context.close();
      }
    }
    
  6. @Profile Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;

    开发环境develop、测试环境test、生产环境master
    数据源:(/dev) (/test) (/master)

    @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件

    • 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
    • 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
    @PropertySource("classpath:/dbconfig.properties")
    @Configuration
    public class MainConfigOfProfile implements EmbeddedValueResolverAware{
    	@Value("${db.user}")
    	private String user;
    	private String driverClass;
    	
    	@Profile("default")
    	@Bean("test")
    	public DataSource testDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
    		ComboPooledDataSource dataSource = new ComboPooledDataSource();
    		dataSource.setUser(user);
    		dataSource.setPassword(password);
    		dataSource.setDriverClass(driverClass);
    		return dataSource;
    	}
    	
    	@Profile("dev")
    	@Bean("dev")
    	public DataSource devDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
    		ComboPooledDataSource dataSource = new ComboPooledDataSource();
    		dataSource.setUser(user);
    		dataSource.setPassword(password);
    		dataSource.setDriverClass(driverClass);
    		return dataSource;
    	}
    	
    	@Profile("master")
    	@Bean("master")
    	public DataSource masterDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
    		ComboPooledDataSource dataSource = new ComboPooledDataSource();
    		dataSource.setUser(user);
    		dataSource.setPassword(password);
    		dataSource.setDriverClass(driverClass);
    		return dataSource;
    	}
    	public void setEmbeddedValueResolver(StringValueResolver resolver) {
    		String driverClass = resolver.resolveStringValue("${db.driverClass}");
    		this.driverClass = driverClass;
    	}
    }
    
    public class IOCTestProfile {
    	//1. 使用命令行动态参数:在虚拟机参数位置加载 -Dspring.profiles.active=test
    	//2. 使用代码的方式激活某种环境;
    	@Test
    	public void test01() {
    		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
    		//1. 创建一个applicationContext
    		//2. 设置需要激活的环境
    		applicationContext.getEnvironment().setActiveProfiles("dev","master");
    		//3. 注册主配置类
    		applicationContext.register(MainConfigOfProfile.class);
    		//4. 启动刷新容器
    		applicationContext.refresh();
    		
    		String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
    		System.out.println(Arrays.toString(beanNamesForType));
    		
    		applicationContext.close();
    	}
     
            @Test
    	public void test02() {
    		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
    		
    		String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
    		System.out.println(Arrays.toString(beanNamesForType));
    		
    		applicationContext.close();
    	}
    }
    
  7. 先创建两个类,不用注解注入到IOC容器中,在应用的时候在导入到当前容器中。

  8. @Conditional 表示组件只有在被具体Condition匹配的情况下才会被注册

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Conditional {
    	// 所有条件都匹配该组件才能被注册
    	Class<? extends Condition>[] value();
    }
    
  9. @PropertySource @ConfigurationProperties(“jdbc”) 示例如下:

    @RestController public class HelloController {
    	@Value("${jdbc.username}")
    	private String username;
    	@Value("${jdbc.password}")
    	private String password;
    	
    	@RequestMapping("/getUandP")
    	public String getProperties() {
    		return username + ":" + password;
    	}
    	@RequestMapping("HELLO")
    	public String say() {
    		return "你好SpringBoot";
    	}
    }
    
    @RestController
    @ConfigurationProperties("jdbc")
    @Setter // 必须有set方法才能批量注入属性
    @RequestMapping("/h2")
    public class HelloController2 {
    	private String username;
    	private String password;
    	
    	@RequestMapping("/getMsg")
    	public String getProperties() {
    		return username + ":" + password;
    	}
    	
    	@RequestMapping("/hello/{test}")
    	public String say(@PathVariable("test") String test) {
    		return "你好SpringBoot  | " + test;
    	}
    }
    
    @RestController
    @Setter
    @RequestMapping("/user/")
    @PropertySource("classpath:/properties/user.properties")
    @ConfigurationProperties(prefix = "cat")
    public class PropertiesController {
    	private Integer id;
    	private String name; 
    	
    	@RequestMapping("getUser")
    	public String getMsg() {
    		return id + ":" + name;
    	}
    }
    
  10. @DependOn控制bean加载顺序,有很多场景需要bean B应该被先于bean A被初始化,从而避免各种负面影响。我们可以在bean A上使用@DependsOn注解,告诉容器bean B应该先被初始化。下面通过示例来说明。

这是一个配置类,配置类之间相互引用,但是又有要求,所以需要DependsOn注解。

publish一定是在listen之前的。适用于观察者模式。

@Configuration
@ComponentScan("com.logicbig.example")
public class AppConfig {
    @Bean(initMethod = "initialize")
    @DependsOn("eventListener")
    public EventPublisherBean eventPublisherBean () {
        return new EventPublisherBean();
    }

    @Bean(name = "eventListener", initMethod = "initialize")
    // @Lazy
    public EventListenerBean eventListenerBean () {
        return new EventListenerBean();
    }

    public static void main (String... strings) {
        new AnnotationConfigApplicationContext(AppConfig.class);
    }
}
发布了18 篇原创文章 · 获赞 7 · 访问量 361

猜你喜欢

转载自blog.csdn.net/weixin_44074551/article/details/104704235