Spring容器初始化源码解析

Spring 源码硬核解析系列专题(一):IoC 容器的初始化过程 Spring 框架作为 Java 生态中最经典的开源项目之一,其核心魅力在于 IoC(控制反转)和 DI(依赖注入)的优雅实现。本系列将深入 Spring 源码,带你从零到一解剖其底层逻辑。本篇作为开篇,我们将聚焦 IoC 容器的初始化过程,以为例,逐步揭开 Spring 启动的神秘面纱。 阅读详情

Spring框架被广泛应用于我们的日常工作中,但是很长时间以来我们都是只会使用,不懂它的作用原理。通过最近一段时间的阅读源码,个人发现通过阅读源码,能够帮助我们了解Spring的设计理念,并且对Java编程中的一些设计模式更加熟悉,所以记录一下自己对Spring源码的理解。

 

在开始进行源码学习前,首先再回顾一下三种Spring编程风格:

1、基于Schemal,即通过xml标签的配置方式

2、基于Annotation的注解技术,使用@Component等注解配置bean

3、基于Java Config,简单来说就是使用@Configuration和@Bean进行配置

基于注解的方式需要通过xml或java config来开启。在使用xml时,需要手动开启对注解的支持:

<context: annotation-config/> 

当然,如果在xml中配置了扫描包,现在也可以光添加下面这一行,这行代码中已经包含了注解的开启功能。

<context: component-sacn base-package="com"/>

如果你使用的是下面AnnotationConfigApplicationContext 这种方式,那么就不需要添加任何操作了,其中已经包含了对注解的支持。

AnnotationConfigApplicationContext ctx=new  AnnotationConfigApplicationContext(SpringConfig.class);

在实际使用过程中,三种方式是可以混合使用的,不存在冲突。按照下面这种方式作为AnnotationConfigApplicationContext 传入的配置文件,即可实现三种风格的统一使用:

@Configuration@ComponentScan("com")@ImportResource("classpath:spring.xml") public class SpringConfig{}

之前也有小伙伴对我说,在开始学习Spring的时候,差点因为配置繁杂的xml被劝退,我也翻阅了一下网上spring入门的技术文章,确实很多还是停留在使用xml的方式上。但是其实如果你翻阅一下spring5的官方文档,可以看出官方是推荐我们使用注解的方式的。尤其是现在的Spring Boot更多的是基于注解,省略了很多配置的过程,对新手更加友好,降低了劝退率,所以本文将基于注解的方式进行源码解析,另外再说明一下本文基于spring-framework-5.0.x源码。

使用注解的方式初始化一个Spring环境,只需要下面一行代码:

AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);

如果看一下它的构造方法,那么可以将它做的工作拆分为三步,为了便于理解可以写成下面的形式,并分为三大模块分别进行说明。

//调用无参构造方法AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext();//注册Configuration配置context.register(SpringConfig.class);//调用核心refresh方法,后面会讲context.refresh();

一、构造方法:

AnnotationConfigApplicationContext继承了GenericApplicationContext,那么我们先看GenericApplicationContext的构造方法:

public GenericApplicationContext() {  this.beanFactory = new DefaultListableBeanFactory();}

在这里初始化了一个beanFactory 的实现类DefaultListableBeanFactory,这就是我们常提到的spring中重要的bean工厂,这里面存放了很多非常重要的数据结构。这里先列出比较重要的beanDefinitionMap,会在后面频繁使用:


//beanDefinitionMap中维护了beanName及BeanDefinition的对应关系。
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
//存放beanName的List
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

从AnnotationConfigApplicationContext的构造方法开始分析:

public AnnotationConfigApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this);
  }

首先实例化了一个AnnotatedBeanDefinitionReader对象,看一下AnnotatedBeanDefinitionReader的构造函数:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {  this(registry, getOrCreateEnvironment(registry));}

为什么在这能够将AnnotationConfigApplicationContext对象作为BeanDefinitionRegistry 传入,回头看一下继承关系那张图,AnnotationConfigApplicationContext继承了BeanDefinitionRegistry,并且最终实现了接口BeanFactory,BeanFactory可以说是Spring中的顶层类,它是一个工厂,能够产生bean对象,提供了一个非常重要的方法getBean,会在后面讲到。到这,我们可以得出一个结论:

BeanDefinitionRegistry可以等同于AnnotationConfigApplicationContext ,看做spring的上下文环境

AnnotatedBeanDefinitionReader在实例化时,会调用registerAnnotationConfigProcessors方法。先看前半段

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
    BeanDefinitionRegistry registry, @Nullable Object source) {
    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
      if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
        beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
      }
      if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
      }
    }

在这里先获取在父类构造函数中实例好的beanFactory ,并为它填充一些属性:

AnnotationAwareOrderComparator:主要用于排序,解析@order和@Priority注解

ContextAnnotationAutowireCandidateResolver:提供处理延迟加载的功能

再看后半段代码,下面生成了6个重要类的BeanDefinitionHolder,并存放到一个Set中,往下看:

Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
    if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
    if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition();
      try {
        def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
            AnnotationConfigUtils.class.getClassLoader()));
      }
      catch (ClassNotFoundException ex) {
        throw new IllegalStateException(
            "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
      }
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }

    return beanDefs;
  }

这里是使用RootBeanDefinition来将普通类转换为BeanDefinition,并进一步封装成BeanDefinitionHolder。封装成BeanDefinitionHolder的操作在registerPostProcessor方法中:

private static BeanDefinitionHolder registerPostProcessor(
      BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
    definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    registry.registerBeanDefinition(beanName, definition);
    return new BeanDefinitionHolder(definition, beanName);
  }

通过registerBeanDefinition方法将BeanDefinition注册到spring环境中,这个操作其实就是执行了上面的beanDefinitionMap的put操作:

this.beanDefinitionMap.put(beanName, beanDefinition);

在上面的操作全部完成后,在还没有实例化用户自定义的bean前,已经有了6个spring自己定义的beanDefinition,用于实现spring自身的初始化:

这里有必要对BeanDefinition进行一下说明,它是对具有属性值的bean实例的一个说明,或者说是定义。就像是在java类加载的过程,普通java文件要先生成字节码文件,再加载到jvm中生成class对象,spring初始化过程中首先要将普通类转化为BeanDefinition,然后再实例化为bean。

在实例化AnnotatedBeanDefinitionReader完成后,实例化了一个ClassPathBeanDefinitionScanner,可以用来扫描包或者类,并将扫描到的类转化为BeanDefinition。但是翻阅源码,我们可以看到实际上扫描包的工作不是这个scanner对象来完成的,而是在后面spring自己实例化了一个ClassPathBeanDefinitionScanner来负责的。

这里的scanner仅仅是对外提供一个扩展,可以让我们能够在外部调用AnnotationConfigApplicationContext对象的scan方法,实现包的扫描,例如:

context.scan("com.hydra");

二、register方法:

到这,AnnotationConfigApplicationContext构造函数执行完毕,调用register方法注册配置类,实际执行方法doRegisterBean:

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
      @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
    //判断这个类是否需要解析,主要根据注解进行判断
    if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
      return;
    }
    abd.setInstanceSupplier(instanceSupplier);
    //得到类的作用域
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    //把类的作用域添加到数据结构中
    abd.setScope(scopeMetadata.getScopeName());
    //生成类的名字,通过beanNameGenerator
    String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
    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);
    }
  
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
  }

在这段代码中,主要完成这几项任务:

1、首先根据我们传入的类创建一个AnnotatedGenericBeanDefinition,它可以理解为一个数据结构,其中包含了类的一些元信息,例如作用域scope,懒加载lazy等属性。

2、调用processCommonDefinitionAnnotations方法,处理类中的通用注解,分析源码得知处理了Lazy,DependsOn,Primary,Role等注解,处理完成后把它们添加到数据结构中。

3、封装成BeanDefinitionHolder,BeanDefinitionHolder可以简单的理解为一个Map,它关联BeanDefinition和beanName。

4、调用registerBeanDefinition方法,将上面的BeanDefinitionHolder注册给registry,这个registry就是 AnnotationConfigApplicationContext,即BeanDefinitionRegistry。

 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {
    this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
  }

这里最终将beanDefinition注册给了之前实例化的beanFactory,beanFactory的实现类为DefaultListableBeanFactory。

到这,我们已经有两种方法将一个类转化为BeanDefinition:

1、通过RootBeanDefinition 的构造方法

2、调用AnnotatedBeanDefinitionReader的register方法

执行完这一步后,可以看到我们的配置类也被放入了beanDefinitionMap,到这里,spring的工厂初始化工作就完成了。

三、refresh 方法

注册完成后,调用核心方法refresh,初始化spring环境:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
      prepareRefresh();
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      prepareBeanFactory(beanFactory);
      try {
        postProcessBeanFactory(beanFactory);
        invokeBeanFactoryPostProcessors(beanFactory);
        registerBeanPostProcessors(beanFactory);
        initMessageSource();
        initApplicationEventMulticaster();
        onRefresh();
        registerListeners();
        finishBeanFactoryInitialization(beanFactory);
        finishRefresh();
      }
  ...

首先可以看到,方法中的代码是被synchronized加锁的,这样做是为了防止一个线程在执行refresh时,其他线程执行spring容器的启动或销毁操作。下面,我们开始分析一下其中重要的方法,重要的注释会写在代码中。

1、prepareRefresh

prepareRefresh方法中为一些启动的准备工作,包括记录启动时间,是否激活标识位,初始化属性源配置等工作


protected void prepareRefresh() {
    // 记录启动时间
    this.startupDate = System.currentTimeMillis();
    // closed 属性设置为 false
    this.closed.set(false);
    //将 active 属性设置为 true
    //上面两个都是 AtomicBoolean类型
    this.active.set(true);

    if (logger.isInfoEnabled()) {
      logger.info("Refreshing " + this);
    }
    //注解模式下此方法为空
    initPropertySources();
    getEnvironment().validateRequiredProperties();
     ...
  }

2、obtainFreshBeanFactory

返回我们之前创建好的DefaultListableBeanFactory实例beanFactory,这里使用的是它的接口ConfigurableListableBeanFactory来进行接收。

  protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
  }

这里进行一下补充,如果是基于xml的配置,那么是在obtainFreshBeanFactory方法中初始化BeanFactory工厂的,并进行bean的加载与注册,这里不再赘述。

3、prepareBeanFactory

准备bean工厂,对功能进行填充,例如配置了一些标准特征,比如上下文的加载器ClassLoader和postProcessor后置处理器。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    beanFactory.setBeanClassLoader(getClassLoader());
    //bean表达式的解释器
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    //bean对象与String类型的转换,例如<property ref="dao">
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));    
    //spring核心代码,添加一个后置管理器
    //能在bean中获得到各种的*Aware
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    //添加了自动注入的忽略列表
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // BeanFactory interface not registered as resolvable type in a plain factory.
    // MessageSource registered (and found for autowiring) as a bean.
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    //添加一个用于ApplicationListener的bean从事件广播器中添加或删除的后置处理器
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }    
    /*
    * 如果自定义的bean中没有名为“systemProperties”和“systemEnvironment”的Bean
    * 则注册两个bean,key为“systemProperties”和“systemEnvironment”,Value为Map
    * 这两个bean就是一些系统配置和系统环境信息
    * */
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
  }

需要说明的是添加后置处理器addBeanPostProcessor方法,在beanFactory中维护了一个spring后置处理器的列表:

private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();

最终调用的是List的add方法,将后置处理器添加到列表的尾部:

this.beanPostProcessors.add(beanPostProcessor);

这里有必要简单的对BeanPostProcessor进行一下说明:

public interface BeanPostProcessor {
  @Nullable
  default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }
  @Nullable
  default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }
}

postProcessBeforeInitialization在类的初始化之前执行,postProcessAfterInitialization在类的初始化之后执行。也就是说spring通过暴露出BeanPostProcessor这个后置处理器,可以让我们去插手bean的初始化过程。

ApplicationContextAwareProcessor实现了这个接口,通过它spring向外暴露了上下文环境ApplicationContext,供我们调用。

4、postProcessBeanFactory

postProcessBeanFactory是一个空的方法,没有任何实现:

/**
   * Modify the application context's internal bean factory after its standard
   * initialization. All bean definitions will have been loaded, but no beans
   * will have been instantiated yet. This allows for registering special
   * BeanPostProcessors etc in certain ApplicationContext implementations.
   * @param beanFactory the bean factory used by the application context
   */
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}

看一下源码中的注释,可理解可以通过子类扩展当前类,添加一些BeanPostProcessor,在BeanDefinition被加载但bean还没有实例化前,执行这些特殊的后置管理器进行功能扩展。

5、invokeBeanFactoryPostProcessors

在该方法中,执行已被注册的BeanFactoryPostProcessor。BeanFactoryPostProcessor也是spring提供的扩展点之一,它运行于spring容器加载了beanDefinition之后,但还未实例化bean之前执行。通过实现这个接口,可以在bean创建之前修改beanDefinition的属性,并且可以同时配置多个BeanFactoryProcessor,通过设置order属性来控制顺序。


@FunctionalInterface
public interface BeanFactoryPostProcessor {
  void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

再来看看invokeBeanFactoryPostProcessors方法:

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());   
    if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
  }

这个需要注意的是getBeanFactoryPostProcessors方法,这个方法是获取手动注册给spring添加的BeanFactoryPostProcessor,这个“手动注册”并不是说写好了以后添加一个@Component注解就可以了,因为如果加了注解还是spring自己去扫描得到的。

看一下getBeanFactoryPostProcessors方法,就可以知道是这里直接返回了一个List:

 public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
    return this.beanFactoryPostProcessors;
  }

而通过 AnnotationConfigApplicationContext的addBeanFactoryPostProcessor方法进行添加,则直接添加进了这个list中:

public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
    Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
    this.beanFactoryPostProcessors.add(postProcessor);
  }

回到代码中,调用执行了PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors 方法,这个方法用于执行所有注册的BeanFactoryPostProcessor。该方法中,创建一个List存放spring内部自己实现了BeanDefinitionRegistryPostProcessor接口的对象,并从beanFactory中获取这个type的bean的名称:


List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
String[] postProcessorNames =
          beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

此处,我们可以得到一个对应的beanName:

在获取到beanName后,通过bean工厂的getBean方法将其实例化,并添加到currentRegistryProcessors中,然后调用invokeBeanDefinitionRegistryPostProcessors方法,执行所有的BeanDefinitionRegistryPostProcessor:

for (String ppName : postProcessorNames) {
  if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    processedBeans.add(ppName);
  }
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
//合并list
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//清除list
currentRegistryProcessors.clear();

看一下currentRegistryProcessors中的实例,这个对象非常重要,会在后面讲到:

回到上面的调用过程,我们知道这个Collection中现在只有一个对象,所以调用的是上面提到的  ConfigurationClassPostProcessor 对象的 postProcessBeanDefinitionRegistry方法:

 private static void invokeBeanDefinitionRegistryPostProcessors(
      Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
    for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {      
      postProcessor.postProcessBeanDefinitionRegistry(registry);
    }
  }

最终调用ConfigurationClassPostProcessor 的processConfigBeanDefinitions

先看方法的前半段:


public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
  //定义一个list,存放beanFactory中的beanDefinition
  List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
  //获取容器中注册的所有beanDefinition的名字,目前有了7个
  String[] candidateNames = registry.getBeanDefinitionNames();
  for (String beanName : candidateNames) {
    BeanDefinition beanDef = registry.getBeanDefinition(beanName);
    if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
        ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
      //如果BeanDefinition中的configurationClass的属性为full或者lite,则意味着已经处理过了,直接跳过
      if (logger.isDebugEnabled()) {
        logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
      }
    }
    //判断是否Configuration类,如果加了Configuration下面的这几个注解就不再判断了
    else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
      configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
    }
  }

  // Return immediately if no @Configuration classes were found
  if (configCandidates.isEmpty()) {
    return;
  }

这里先读取了BeanFactory中存放的7个beanDefinition,然后去判断是否加了以下注解:

@Configuration
@ComponentScan
@Import
@ImportResource

如果是,则添加到configCandidates的List中,运行到这,可以看到在里面存了一个我们自定义的添加了@Configuration注解的类:

向下运行,首先实例化了一个ConfigurationClassParser,用于解析各个配置类:

ConfigurationClassParser parser = new ConfigurationClassParser(        this.metadataReaderFactory, this.problemReporter, this.environment,        this.resourceLoader, this.componentScanBeanNameGenerator, registry);

然后,实例化 2个Set,candidates 用于将之前加入的configCandidates进行去重,因为有可能有多个配置类重复了。alreadyParsed 用于判断是否处理过,避免重复。

Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());

调用ConfigurationClassParser的parse方法:​​​​​​​

do {      parser.parse(candidates);      ...}while (!candidates.isEmpty());

parse方法调用链较长,这里只列出其调用过程和重要扫描过程:


ConfigurationClassParser 
# parse(Set<BeanDefinitionHolder> configCandidates)
# parse(AnnotationMetadata metadata, String beanName)
# processConfigurationClas(ConfigurationClass configClass)
# doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)

重点看一下doProcessConfigurationClass方法:​​​​​​​

Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(      sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);

得到注解类的注解信息,例如basePackage等,存放在AnnotationAttributes中。之后对set进行遍历:


for (AnnotationAttributes componentScan : componentScans) {
  //扫描普通类,会扫描出来所有加了@Component注解的类
  //并且把扫描出来的普通bean放到map当中
  Set<BeanDefinitionHolder> scannedBeanDefinitions =
      this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
  //这一步完成后扫描出来了所有类
  //检查扫描出的类是否还有 @Configuration
  for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
    BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
    if (bdCand == null) {
      bdCand = holder.getBeanDefinition();
    }
    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
      parse(bdCand.getBeanClassName(), holder.getBeanName());
    }
  }
}

这里的关键还是parse方法,调用ComponentScanAnnotationParser 的parse方法,然后调用ClassPathBeanDefinitionScanner的doScan方法,实现扫描核心功能:


protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
  Assert.notEmpty(basePackages, "At least one base package must be specified");
  Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
  for (String basePackage : basePackages) {
    //扫描basePackage路径下的java文件
    //并把它转成BeanDefinition类型
    Set<BeanDefinition> candidates = findCandidateComponents(basePackage);

    for (BeanDefinition candidate : candidates) {
      //解析scope属性
      ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
      candidate.setScope(scopeMetadata.getScopeName());
      String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

      //所有扫描出来的类 是 ScannedGenericBeanDefinition  ,符合AbstractBeanDefinition
      //先设置默认值
      if (candidate instanceof AbstractBeanDefinition) {
        //如果这个类是AbstractBeanDefinition的子类
        //则为他设置默认值,比如lazy,init ,destroy
        postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
      }
      if (candidate instanceof AnnotatedBeanDefinition) {
        //检查并且处理常用的注解
        //这里的处理主要是指把常用注解的值设置到AnnotatedBeanDefinition当中
        //当前前提是这个类型必须是AnnotatedBeanDefinition类型的,也就是加了注解的类
        AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
      }
      if (checkCandidate(beanName, candidate)) {
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
        definitionHolder =
            AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        beanDefinitions.add(definitionHolder);
        //加入到BeanDefinitionMap当中
        registerBeanDefinition(definitionHolder, this.registry);
      }
    }
  }
  return beanDefinitions;
}

到这,spring已经把所有加了@Component类注解的类扫描出来,并生成对应的beanDefinition,最后通过registerBeanDefinition方法,放入beanDefinitionMap中。

到这,我们执行完了ConfigurationClassPostProcessor的invokeBeanDefinitionRegistryPostProcessors方法。

回到PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法中继续向下执行:​​​​​​​

invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);

第二行语句用于执行我们自定义的beanFactoryPostProcessor,由于现在不存在,可以直接忽略,重点看第一条。

有的同学可能会问,刚才不是执行了一条差不多的语句吗,而且这个registryProcessors里面的东西也没有变,还是ConfigurationClassPostProcessor,那么为什么要执行两遍?看一下继承关系:

BeanDefinitionRegistryPostProcessor对BeanFactoryPostProcessor 进行了扩展,添加了自己的方法。所以第一次执行的是:

BeanDefinitionRegistryPostProcessor # postProcessBeanDefinitionRegistry

而第二次执行的方法是:

BeanFactoryPostProcessor # postProcessBeanFactory

这里调用了ConfigurationClassPostProcessor的postProcessBeanFactory方法:

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    int factoryId = System.identityHashCode(beanFactory);
    if (this.factoriesPostProcessed.contains(factoryId)) {
      throw new IllegalStateException(
          "postProcessBeanFactory already called on this post-processor against " + beanFactory);
    }
    this.factoriesPostProcessed.add(factoryId);
    if (!this.registriesPostProcessed.contains(factoryId)) {
      // BeanDefinitionRegistryPostProcessor hook apparently not supported...
      // Simply call processConfigurationClasses lazily at this point then.
      processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
    }
   
    enhanceConfigurationClasses(beanFactory);
    beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
  }

 主要用于给我们的@Configuration配置类产生cglib代理,并添加一个ImportAwareBeanPostProcessor后置处理器,这个后置处理器会在后面实例化bean的过程中用到。

6、registerBeanPostProcessors

这一步用于向spring环境中注册BeanPostProcessors后置处理器,前面说过,BeanPostProcessors的作用是在bean初始化的时候允许我们人工进行插手,当然这里只是进行一个注册的过程,并不会实际执行,具体的执行是bean在初始化的时候。​​​​​​​

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {  PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);}

调用registerBeanPostProcessors方法:​​​​​​​

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

首先从BeanDefinitionMap中找出所有实现BeanPostProcessor接口的类,并添加了一个BeanPostProcessorChecker到beanFactory中,主要用于记录信息。

然后,创建了4个List用于缓存不同类型的后置处理器:


//存放实现PriorityOrdered接口的BeanPostProcessor
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
//存放Spring内部的BeanPostProcesso
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
//存放注册实现Ordered接口的BeanPostProcessors
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
//存放常规的BeanPostProcessors
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();

对4个List分别调用PostProcessorRegistrationDelegate的registerBeanPostProcessors方法:

  private static void registerBeanPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
    for (BeanPostProcessor postProcessor : postProcessors) {
      beanFactory.addBeanPostProcessor(postProcessor);
    }
  }

遍历列表,调用AbstractBeanFactory的addBeanPostProcessor方法,将后置处理器加到beanPostProcessors中:

 public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
    Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
    // 如果beanPostProcessor已经存在则移除
    this.beanPostProcessors.remove(beanPostProcessor);   
    // beanFactory是否已注册过InstantiationAwareBeanPostProcessors
    if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
      this.hasInstantiationAwareBeanPostProcessors = true;
    }
    //beanFactory是否已注册过DestructionAwareBeanPostProcessor
    if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
      this.hasDestructionAwareBeanPostProcessors = true;
    }
    //将beanPostProcessor添加到beanPostProcessors中
    this.beanPostProcessors.add(beanPostProcessor);
  }

在这个方法中,如果beanPostProcessor已经存在则移除,这样做可以起到重排序的作用,如果beanPostProcessor原先在前面,经过删除后再添加,则变到最后面。到这,将所有实现了BeanPostProcessor接口的类加载到 BeanFactory 中。

7、非重点部分

以下部分是非重点部分,不需要过分关注,因此省略,只做一个大体的注释说明:

//初始化上下文的 MessageSource源
initMessageSource();
//初始化应用事件广播器
initApplicationEventMulticaster();
//空方法,可用做子类扩展
onRefresh();
//在所有注册的bean中查找Listener bean,注册到消息广播器中
registerListeners();

至此,Spring环境的初始化工作就做完了,但是bean还没有被创建出来,下篇文章,我们讲讲Spring中bean的实例化过程。

如果您喜欢这篇文章,欢迎关注订阅我的微信公众号 “码农参上”,不定时发布最新文章

公众号后台回复“面试”获取海量大厂面试资料​​​​​​​

Spring 源码分析(Bean的初始化) Spring 源码分析(Bean的初始化) 前言 本篇文章是个人第一次看spring源码并总结,同时也参考了下面这篇博客。基本也是按照他的思路来理解的。这也算是第一版个人简易理解。也算是窥见spring的冰山一角,之后也会继续阅读下去。望各位多多支持。 本片博文如有错误之处,还请多多指正,共同学习。 博文直接从ClassPathXmlApplicationContext开始分析,后续会总结基于注解的AnnotationConfigApplicationContext来分析 spring-ioc javadoop Bean的初始化 } level; then parses the contain 立即下载

相关推荐

Jenkins+docker 微服务实现自动化部署安装和部署过程

本文详细介绍了如何使用Docker部署Jenkins自动化服务器。主要内容包括:1)拉取Jenkins官方或BlueOcean镜像;2)创建容器并配置端口映射、数据卷挂载;3)设置防火墙规则;4)配置清华大学镜像加速;5)安装必要插件;6)SSH密钥配置;7)构建触发器设置;8)编写自动化构建脚本。通过Docker部署Jenkins可以简化安装流程,确保环境一致性,并利用容器特性实现快速启动和管理。文章提供了完整的配置步骤和注意事项,帮助用户快速搭建CI/CD环境。

qq_33665793的博客 1688

AnnotationConfigUtils 处理注解Bean 定义类中的通用注解

AnnotationConfigUtils 类的processCommonDefinitionAnnotations()在向容器注册Bean 之前,首先对注解Bean 定义类中的通用Spring 注解进行处理,源码如下: //处理Bean定义中通用注解 static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) { AnnotationAttrib

Leon_Jinhai_Sun的博客 468

MPU6050的四元数解算姿态方法

使用MPU6050硬件DMP解算姿态是非常简单的,下面介绍由三轴陀螺仪和加速度计的值来使用四元数软件解算姿态的方法。 我们先来看看如何用欧拉角描述一次平面旋转(坐标变换): MPU6050的四元数解算姿态方法 设坐标系绕旋转α角后得到坐标系,在空间中有一个矢量在坐标系中的投影为,在内的投影为由于旋转绕进行,所以Z坐标未变,即有。 转换成矩阵形式表示为: 即 所以从旋转到可以写成上面仅仅是绕一根轴的旋转,如果三维空间中的欧拉角旋转要转三次: MPU6050的四元数解算姿态方法 上面得到了一个表示旋转的方

qq_41938005的博客 8392

spring5.2.x源码阅读笔记-AnnotationConfigApplicationContext构建(二)register(componentClasses)

接上一篇,使用同样的测试用例 代码块1:register(Class<?>... componentClasses) public void register(Class<?>... componentClasses) { Assert.notEmpty(componentClasses, "At least one component class must be specified"); this.reader.register(componentClasses);

weixin_43836063的博客 1398

MFC使用Websocket通讯介绍和实例(附完整源码)

踩坑点,下载了好几个boost版本编译,经常出问题,后来搜索了好久资料才发现如下评论:WebSocket++0.8.2 has been tested through Boost 1.72。WebSocketpp依赖于boost,因此在使用WebSocketpp前需要编译Boost;所以我们直接下载Boost 1.72的windows版的进行安装,安装完成还需要编译;WebSocketpp也叫WebSocket++;服务编译好之后,使用。

weixin_42530684的博客 1171

45个经典Linux面试题(非常详细)零基础入门到精通,收藏这一篇就够了

(文件系统分配其中的一些磁盘块用来记录它自身的一些数据,如 i 节点,磁盘分布图,间接块,超级块等。$ chmod 751 file 给 file 的属主分配读、写、执行(7)的权限,给 file 的所在组分配读、执行(5)的权限,给其他用户分配执行(1)的权限。linux命令’hash’管理着一个内置的哈希表,记录了已执行过的命令的完整路径, 用该命令可以打印出你所使用过的命令以及执行的次数。创建文件:典型的如 touch,vi 也可以创建文件,其实只要向一个不存在的文件输出,都会创建文件。

小陈的博客 2070

ConfigurationClassPostProcessor —— Spring中最!最!最!重要的后置处理器!没有之一!!!

0. 疑惑 在阅读本文之前,可以先思考一下以下几个问题。 (1) @Configuration注解的作用是什么,Spring是如何解析加了@Configuration注解的类? (2) Spring在什么时候对@ComponentScan、@ComponentScans注解进行了解析? (3) Spring什么时候解析了@Import注解,如何解析的? (4) Spring什么...

z69183787的专栏 1670

ubuntu安装eigen3.3.7

查看已安装版本: gedit /usr/include/eigen3/Eigen/src/Core/util/Macros.h 或 gedit /usr/local/include/eigen3/Eigen/src/Core/util/Macros.h 卸载先前版本: sudo updatedb locate eigen3 得到eigen库的位置 卸载: sudo rm -rf /usr/include/eigen3 /usr/lib/cmake/eigen3 ...

reason的博客 1万+

SpringBoot初始化过程核心源码剖析

首先我们启动一个SpringBoot项目是怎么启动的?这个方法来进行启动的,很多人都对这个有点误解,以为是@SpringBootApplication赋予的超能力,所以就让Main方法成了SpringBoot启动类,我们下面就来刨析在我们的SpringBoot启动的过程中,经过了哪些步骤为什么在类上写个注解就能将其注入到Spring容器当中,以及说我们的自动配置是怎样实现的等等;第二是调用了重载的run方法并且返回(我们项目中的所有需要注入到IOC容器的类、自动配置都是在这个方法中被调用执行的);

JAVA_EE_J的博客 876

手把手教你为RK3588开发板适配RTL8211F网卡:设备树配置与PHY驱动匹配全流程

本文详细介绍了在RK3588开发板上适配RTL8211F千兆以太网PHY芯片的全流程,包括硬件原理图确认、设备树配置与PHY驱动匹配。通过实战案例和调试技巧,帮助开发者解决常见问题并优化网络性能,适用于嵌入式Linux开发中的Ethernet网络功能实现。

weixin_29184075的博客 526

基于STM32、HAL库的IP5356M快充协议芯片简介及驱动程序设计

@param hip: IP5356M句柄指针。* @param hip: IP5356M句柄指针。* @param hip: IP5356M句柄指针。* @param hip: IP5356M句柄指针。* @param hip: IP5356M句柄指针。* @param hip: IP5356M句柄指针。* @param hip: IP5356M句柄指针。* @param hip: IP5356M句柄指针。* @param hip: IP5356M句柄指针。

corlin6688的博客 1220

Spring ioc 初始化流程(源码)

【重点跟踪】方法说明:* 【核心方法】:该方法表示初始化(或者重建)ioc容器。即可以把原来的ApplicationContext销毁,重新执行初始化创建// 创建ioc容器,同步加锁,保障线程安全 synchronized(this . startupShutdownMonitor) {/*** 1.刷新预处理* 准备工作:记录容器启动的时间,和状态标记/*** 2.阅读XML中的信息,注册BeanDefinition(重点)

weixin_43811057的博客 592

WEB浏览器视频流播放方案

基于Media Source Extensions播放视频流 浏览器播放视频的几种方法 一、H5 video标签 在浏览器播放视频,可以使用HTML5原生的video标签。但其播放的格式使用一定限制的,目前video只支持三种格式WebM、Ogg、MP4。 WebM:WebM 文件使用 VP8 视频编解码器和 Vorbis 音频编解码器 Ogg :Ogg 文件使用 Theora 视频编解码器和 Vorbis音频编解码器 MP4: MPEG 4文件使用 H264 视频编解码器和AAC音频编解码器 上面三种

machh的专栏 2381

Spring源码解析一:容器初始化

超详细Spring源码解析一:容器初始化 学习java也有几个月了,之前学习完Spring的源码一直没有时间总结(主要是懒),今天抽空回头做了一下复习,就想着将Spring源码的解析和理解分享出来,可能会有不贴切的地方还希望看客海涵指出。 前言 首先让我们看看当我们实例化一个容器时,spring做了什么 //这是我们常用的实例化方式 AnnotationConfigApplicationCon...

weixin_44130043的博客 367

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Spring源码解析一 (IOC容器初始化深度解析)

IOC容器的初始化的三种方式 XmlBeanFactory ClassPathXmlApplicationContext AnnotationConfigApplicationContext 三种初始化方式流程图: 分析: 由调用图可以看到不论使用哪一种方式去初始化IOC容器, 注册BeanDefinition的工作都是由DefaultListableBeanFactory的r...

AN_ERA的博客 1265

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Spring注解驱动开发第46讲——Spring IOC容器创建源码解析(六)之初始化所有剩下的单实例bean(上)

写在前面 在前面几讲中,我们已经对IOC容器创建过程中的大部分方法进行过研究,其中比较核心的方法就是如下两个: invokeBeanFactoryPostProcessors方法:该方法在《Spring注解驱动开发第42讲——Spring容器创建源码解析(二)之执行BeanFactoryPostProcessor》这一讲中已经详细讲过了,要是还有不清楚的同学,可以查阅这篇文章哟! registerBeanPostProcessors方法:该方法在《Spring注解驱动开发第43讲——Spring容器创建源

李阿昀的博客 1866

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Spring IoC - IoC 容器初始化 源码解析

前言 本章主要内容是由以下部分组成, Spring 中容器初始化入口 以最经典的ClassPathXmlApplicationContext 为例,讲解Spring IoC 的容器初始化过程 在学习源码的过程当中,我想强调两点: 一定要学会抓重点,归纳核心类、核心方法、核心步骤。 理解类、变量、方法名的命名,Spring 源码的命名是很讲究的,很多时候是自解释的 一定要学会看Java do...

Richard Program Studio 377

Spring源码解析之IOC容器初始化

目录什么是IOCSpring IOC体系架构BeanFactoryBeanDefinitionBeanDefinitionReaderIOC容器的初始化 什么是IOC IOC(inversion of control)控制反转,所谓控制反转就是把我们原先代码中需要实现的对象创建,反转给容器来实现,必然的我们需要创建一个容器,同样的需要一种描述让容器知道需要创建对象和对象之前的关系,这个描述的具体表现就是我们可配置的文件。 DI(Dependency injection)依赖注入:就是对象是被动接受依赖类而不

陆林烽的博客 759

Spring容器初始化源码全解析

全网最全Spring初始化源码解析

qq_39639186的博客 681

【spring源码解析】spring容器初始化过程

SpringIOC容器加载原理 一 Spring容器框架 如上图所示,我们可以看到Spring初始化的架构原理,如上图所示通过不同的bean的定义方式,比如xml配置的方式,注解配置的方式,可能后面还有相信的扩展bean的定义方式,这个它是怎么工作呢,总的框架来说,无非是制作一层读取配置的抽象类BeanDefinationReader,以不同的方式读取配置,然后生成不同的beanDefination放到了beanDefinitionMap的bean容器池中。用到的时候再从beanDefinition

worn_xiao的博客 1999

Spring源码解析 - IOC容器的初始化过程 (一)

Spring的开始 Spring框架是一种分层架构,它包含了一系列的功能,大概由20种模块组成。 这些模块分为核心容器(Core Container), 数据访问/集成(Data Access/Integration), Web, AOP, 工具(Instrumentation), 消息(Messaging), 测试用例(Test). Spring的代码量非常庞大,对于大多数第一次看spring源码的读者来说,会感觉到一头雾水,不知从哪里看起。 其实很简单,当要看一个框架源码的时候,先要熟悉这个框架的简单使

weixin_45081001的博客 189

Spring源码解析二:Spring IOC容器的初始化

IOC容器的初始化分为三个步骤 Resource定位,即BeanDefinition的资源定位。 BeanDefinition的载入 向IOC容器注册BeanDefinition 1,Resource定位 以ApplicationContext的具体实现FileSystemXmlApplicationContext来介绍Resource定位的过程: IOC容器初始化类比为用木桶来装水,Res...

♾️ 1070

spring容器初始化,bean加载生成过程,源码解析学习

最近学习的spring源码解析系列,做个记录Spring源码分析2 — 容器启动流程Spring源码分析3 — spring XML配置文件的解析流程Spring源码分析4 — spring bean创建和初始化...

mafei6827的博客 401

spring容器ApplicationContext初始化源码解析

测试用例: public class BaseTest { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config.xml"); TestBean testBean = context.getBean("testBean", TestBean.class); t

qq_42842433的博客 349

spring ioc容器创建与bean初始化源码解析1:beanFactory容器的创建及初始化

spring容器创建及bean初始化过程 分为6个部分 1.beanFactory容器的创建及初始化 2.在beanFactory容器初始化之后定制和修改BeanFactory内容 3.注册BeanPostProcessor(作用在bean创建的过程中进行拦截,从而执行指定逻辑) 4.初始化MessageSource ApplicationEventMulticaster App...

u013905744的专栏 514
上一篇: 基于Netty,20分钟手撸一个RPC框架
下一篇: Spring实例化Bean源码解析
码农参上
博客等级 码龄17年 9050粉丝 77原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值