温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Spring5.x 中容器启动源码怎么写

发布时间:2021-09-26 14:13:29 来源:亿速云 阅读:127 作者:柒染 栏目:大数据

今天就跟大家聊聊有关 Spring5.x 中容器启动源码怎么写,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

Spring 已经是十分成熟的一个框架,此篇为开天辟地的Spring源码分析首发。读源码本来就是一件十分枯燥,具有一定难度,技巧性的有重要意义的事。万事开头难,我会利用空余时间持续的跟进文章的连载。对于喜爱源码的小伙伴,能够提供一定的帮助。

最简单的启动spring的代码如下:

import com.ld.test.config.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestDemo {
  public static void main(String[] args) {
      AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(AppConfig.class);
      acac.close();
  }
}
  • AnnotationConfigApplicationContext

先来看一下AnnotationConfigApplicationContext类的UML图,留个印象。

Spring5.x 中容器启动源码怎么写

点开AnnotationConfigApplicationContext(AppConfig.class);方法查看源码:

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {

    // 调用默认无参构造器,里面有一大堆初始化逻辑
    // 开天辟地初始化两个类
    // AnnotatedBeanDefinitionReader reader;
    // ClassPathBeanDefinitionScanner scanner;
    this();

    // 把传入的Class进行注册,Class既可以有@Configuration注解,也可以没有@Configuration注解
    //
    // 有@Configuration
    // map.put("org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass","full")
    // 没有有@Configuration
    // map.put("org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass","lite")
    //
    // 怎么注册? 委托给了 org.springframework.context.annotation.AnnotatedBeanDefinitionReader.register 方法进行注册
    // 传入Class 生成  BeanDefinition , 然后通过 注册到 BeanDefinitionRegistry
    register(annotatedClasses);

    // 刷新容器上下文
    refresh();
}

该构造器允许我们传入一个或者多个class对象。class对象可以是被@Configuration标注的,也可以是一个普通的Java 类。

有参构造器调用了无参构造器,点开源码:

public AnnotationConfigApplicationContext() {
    // 隐式调用父类构造器,初始化beanFactory,具体实现类为DefaultListableBeanFactory
    // super();

    // 创建 AnnotatedBeanDefinitionReader,
    // 创建时会向传入的 BeanDefinitionRegistry 中 注册 注解配置相关的 processors 的 BeanDefinition
    this.reader = new AnnotatedBeanDefinitionReader(this);

    // 通过后面的源码探究也可以发现,spring并不是使用这个scanner来扫描包获取Bean的
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}

初始化子类时会先初始化父类,会默认调用父类无参构造器。AnnotationConfigApplicationContext继承了GenericApplicationContext,在GenericApplicationContext的无参构造器中,创建了BeanFactory的具体实现类DefaultListableBeanFactory。spring中的BeanFactory就是在这里被实例化的,并且使用DefaultListableBeanFactory做的BeanFactory的默认实现。

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

Spring5.x 中容器启动源码怎么写

AnnotationConfigApplicationContext的构造器中还创建了两个对象:AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner。

  • ClassPathBeanDefinitionScanner scanner

先说scanner的作用,通过查看源码可以发现,这个scanner只有在手动调用AnnotationConfigApplicationContext的一些方法的时候才会被使用(通过后面的源码探究也可以发现,spring并不是使用这个scanner来扫描包获取Bean的)

Spring5.x 中容器启动源码怎么写

2、AnnotatedBeanDefinitionReader

创建AnnotatedBeanDefinitionReader对象。spring在创建reader的时候把this当做了参数传给了构造器。也就是说,reader对象里面包含了一个this对象,也就是AnnotationConfigApplicationContext对象。AnnotationConfigApplicationContext 实现了BeanDefinitionRegistry接口。点开this.reader = new AnnotatedBeanDefinitionReader(this);源码:

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

从传入的BeanDefinitionRegistry对象,也就是AnnotationConfigApplicationContext对象中获取Environment(共用同一个Environment),然后又接着调用另一个构造器。点开源码:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    Assert.notNull(environment, "Environment must not be null");
    this.registry = registry;
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);

    //在 BeanDefinitionRegistry 中注册 注解配置相关的 processors
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

在这个构造器中,执行了一个非常重要的方法AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); 顾名思义,spring通过这个方法注册了解析注解配置相关的处理器。点开源码:

第一步:设置属性

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {

    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
        if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {

            // AnnotationAwareOrderComparator是OrderComparator的子类,用来支持Spring的Ordered类、@Order注解和@Priority注解。
            beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
        }
        if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {

            // 设置依赖注入的候选处理器
            // 可以看到只要不是ContextAnnotationAutowireCandidateResolver类型  直接升级为最强类型
            beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        }
    }
    // 代码省略。。。
}

注册的是一些spring内置的PostProcessor的BeanDefinition

2.1、 ConfigurationClassPostProcessor

ConfigurationClassPostProcessor是一个BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor处理器,BeanDefinitionRegistryPostProcessor的处理方法能处理@Configuration等注解。ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法内部处理@Configuration,@Import,@ImportResource和类内部的@Bean。

ConfigurationClassPostProcessor类继承了BeanDefinitionRegistryPostProcessor。BeanDefinitionRegistryPostProcessor类继承了BeanFactoryPostProcessor。通过BeanDefinitionRegistryPostProcessor可以创建一个特别后置处理器来将BeanDefinition添加到BeanDefinitionRegistry中。它和BeanPostProcessor不同,BeanPostProcessor只是在Bean初始化的时候有个钩子让我们加入一些自定义操作;而BeanDefinitionRegistryPostProcessor可以让我们在BeanDefinition中添加一些自定义操作。在Mybatis与Spring的整合中,就利用到了BeanDefinitionRegistryPostProcessor来对Mapper的BeanDefinition进行了后置的自定义处理。

2.2、AutowiredAnnotationBeanPostProcessor

AutowiredAnnotationBeanPostProcessor是用来处理@Autowired注解和@Value注解的

2.3、RequiredAnnotationBeanPostProcessor

RequiredAnnotationBeanPostProcessor这是用来处理@Required注解

2.4、CommonAnnotationBeanPostProcessor

提供对JSR-250规范注解的支持@javax.annotation.Resource、@javax.annotation.PostConstruct和@javax.annotation.PreDestroy等的支持。

2.5、EventListenerMethodProcessor

EventListenerMethodProcessor提供@PersistenceContext的支持。

EventListenerMethodProcessor提供@ EventListener 的支持。@ EventListener实在spring4.2之后出现的,可以在一个Bean的方法上使用@EventListener注解来自动注册一个ApplicationListener。

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {

    // 代码省略。。。。

    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

    // 第一个问题 了解 RootBeanDefinition - > AbstractBeanDefinition
    // 第二个问题 了解 registerPostProcessor();
    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {

        //org.springframework.context.annotation.internalConfigurationAnnotationProcessor - ConfigurationClassPostProcessor.class
        //这个类非常的重要,它是一个 BeanDefinitionRegistryPostProcessor

        RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // 代码省略。。。。 逻辑差不多

    return beanDefs;
}

我们发现:内部定义的class都是带internal的

Spring5.x 中容器启动源码怎么写 beanDefs">

1、该方法从传入的BeanDefinitionRegistry对象,也就是AnnotationConfigApplicationContext对象中获取到DefaultListableBeanFactory对象。

2、为获取的DefaultListableBeanFactory对象设置属性

3、往DefaultListableBeanFactory对象中注册BeanDefinition,注册的是一些spring内置的PostProcessor的BeanDefinition(关于BeanDefinition的介绍下期在讲)。注意,此时只是注册BeanDefinition,并没有实例化bean。默认情况下,执行完该方法后,spring容器中所注册的BeanDefinition为:

2.1、注册内置Processor至容器

definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

ROLE_INFRASTRUCTURE = 2 就是我这Bean是Spring自己的,和你用户没有一毛钱关系

private static BeanDefinitionHolder registerPostProcessor(
        BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

    definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    registry.registerBeanDefinition(beanName, definition);
    return new BeanDefinitionHolder(definition, beanName);
}

所谓的注册BeanDefinition,简单理解就是将BeanDefinition放到DefaultListableBeanFactory.registerBeanDefinition对象的beanDefinitionMap中

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {

    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");

    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                    "Validation of bean definition failed", ex);
        }
    }

    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);

    //第一次进来existingDefinition肯定为null
    if (existingDefinition != null) {
        // 代码省略。。。
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
        if (hasBeanCreationStarted()) {
            // Cannot modify startup-time collection elements anymore (for stable iteration)
            synchronized (this.beanDefinitionMap) {
                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);
            this.beanDefinitionNames.add(beanName);
            removeManualSingletonName(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }

    if (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}

到此为止:DefaultListableBeanFactory.beanDefinitionMap 只有默认的spring beanDefinition

====下面是大家熟悉的注册默认6大后置处理器:====

  • 1.ConfigurationClassPostProcessor

  • 2.AutowiredAnnotationBeanPostProcessor

  • 3.CommonAnnotationBeanPostProcessor

  • 4.Jpa的PersistenceAnnotationProcessor(没导包就不会注册)

  • 5.EventListenerMethodProcessor

  • 6.DefaultEventListenerFactory

3、ClassPathBeanDefinitionScanner

public AnnotationConfigApplicationContext() {

  /**
    * 创建一个读取注解的Bean定义读取器
    * 什么是bean定义?BeanDefinition
    *
    * 完成了spring内部BeanDefinition的注册(主要是后置处理器)
    */
  this.reader = new AnnotatedBeanDefinitionReader(this);

  /**
    * 创建BeanDefinition扫描器
    * 可以用来扫描包或者类,继而转换为bd
    *
    * spring默认的扫描包不是这个scanner对象
    * 而是自己new的一个ClassPathBeanDefinitionScanner
    * spring在执行工程后置处理器ConfigurationClassPostProcessor时,去扫描包时会new一个ClassPathBeanDefinitionScanner
    *
    * 这里的scanner仅仅是为了程序员可以手动调用AnnotationConfigApplicationContext对象的scan方法
    *
    */
  this.scanner = new ClassPathBeanDefinitionScanner(this);
}

下一步

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
			Environment environment, @Nullable ResourceLoader resourceLoader) {

	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	this.registry = registry;

	// 这个肯定成功
	if (useDefaultFilters) {

		/**
		 * 注册spring扫描类过滤器
		 * 加了特定注解的类会被扫描到
		 * 带有@Component、@Repository、@Service、@Controller、@ManagedBean、@Named
		 */
		registerDefaultFilters();
	}
	setEnvironment(environment);
	setResourceLoader(resourceLoader);
}

只关心最后一个构造函数的registerDefaultFilters();方法

/**
 * 注册过滤器
 * 带有@Component、@Repository、@Service、@Controller、@ManagedBean、@Named
 * 注解的类会被spring扫描到
 * 
 * Register the default filter for {@link Component @Component}.
 * <p>This will implicitly register all annotations that have the
 * {@link Component @Component} meta-annotation including the
 * {@link Repository @Repository}, {@link Service @Service}, and
 * {@link Controller @Controller} stereotype annotations.
 * <p>Also supports Java EE 6's {@link javax.annotation.ManagedBean} and
 * JSR-330's {@link javax.inject.Named} annotations, if available.
 *
 */
@SuppressWarnings("unchecked")
protected void registerDefaultFilters() {
	this.includeFilters.add(new AnnotationTypeFilter(Component.class));
	ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
	try {
		this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
		logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
	}
	catch (ClassNotFoundException ex) {
		// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
	}
	try {
		this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
		logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
	}
	catch (ClassNotFoundException ex) {
		// JSR-330 API not available - simply skip.
	}
}

扫描过滤器includeFilters与excludeFilters

首先这里的includeFilters大家熟悉吗,还有个excludeFilters,先看一下属性

	private final List<TypeFilter> includeFilters = new LinkedList<>();

	private final List<TypeFilter> excludeFilters = new LinkedList<>();

这里提前往includeFilters里面添加需要扫描的特定注解

1.添加元注解@Component,需要注意的是@Repository、@Service、@Controller里面都标注了@Component。很好理解,扫描的时候用includeFilters 去过滤时,会找到并处理这4个注解的类。

2.下面两个注解@ManagedBean、@Named需要有对应的jar包,否则(也就是说把这个方法走完),includeFilters里面只会有一个元素

Spring5.x 中容器启动源码怎么写

this.reader = new AnnotatedBeanDefinitionReader(this); 完成了spring内部BeanDefinition的注册(主要是后置处理器)

1、beanDefinitionMap存放了所有的Defintion 以 key-value

2、List<String> beanDefinitionNames 存放了所有的beanDefintion名字

this.scanner = new ClassPathBeanDefinitionScanner(this);

1、这里的scanner仅仅是为了程序员可以手动调用AnnotationConfigApplicationContext对象的scan方法

2、提供了includeFilters 和 excludeFilters 这里是一个扩展点

看完上述内容,你们对 Spring5.x 中容器启动源码怎么写有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI