您现在的位置是:首页 > 正文

Spring IOC源码分析(基于注解)上

2024-02-29 12:25:20阅读 2

1 入口代码

public class Info {

   public static void main(String[] args) {
      ApplicationContext ac  = new AnnotationConfigApplicationContext(AppConfig.class);
      System.out.println(ac.getBean(AppConfig.class).name);
   }
}

2 AnnotationConfigApplicationContext

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		this();
		register(componentClasses);
		refresh();
	}

调用this(),默认无参的构造方法。AnnotationConfigApplicationContext继承GenericApplicationContext。因此在调用自身构造器的时候会隐式的调用父类的构造器。

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

因此在GenericApplicationContext的构造器完成了DefaultListableBeanFactory的初始化。

/**
	 * 这里会首先初始化父类的构造方法
	 * public GenericApplicationContext() {
	 * 		this.beanFactory = new DefaultListableBeanFactory();
	 * }
	 * 因此会实例化beanFactory,也就是DefaultListableBeanFactory
	 */
	public AnnotationConfigApplicationContext() {
		StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
		// 基于注解的bean定义读取器
		this.reader = new AnnotatedBeanDefinitionReader(this);
		createAnnotatedBeanDefReader.end();
		// 基于注解的bean定义扫描器
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

这里AnnotationConfigApplicationContext有两个属性,bean定义读取器和扫描器。

    private final AnnotatedBeanDefinitionReader reader;

	private final ClassPathBeanDefinitionScanner scanner;

在构造器中开始初始化。

2.1 初始化AnnotatedBeanDefinitionReader

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

这里的BeanDefinitionRegistry是AnnotationConfigApplicationContext实例。因为AnnotationConfigApplicationContext实现了BeanDefinitionRegistry接口。这里的构造器也是门面方法。真正调用的是如下的构造器。

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		//TODO 省略断言
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

这里的conditionEvaluator是条件计算器。什么条件呢。按照一定的条件进行判断,需要注入的Bean满足给定条件才可以注入到Spring IOC容器中。一般使用@Conditional注解。而使用该注解需要实现Condition接口,并重写方法来自定义match规则。conditionEvaluator 的实例化完成之后,存在五个引用。分别是读取到的:

  1. registry=AnnotationConfigApplicationContext
  2. beanFactory=DefaultListableBeanFactory
  3. environment=StandardEnvironment
  4. 资源加载器
  5. 类加载器

第三行代码:AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);作用是注册注解配置处理器。在给定的注册表中注册所有相关的注解后处理程序。也就是说注解配置读取完成之后然后根据注解上下文AnnotationConfigApplicationContext的情况进行之后的配置。称之为后处理器。具体的实现在AnnotationConfigUtils类里面;

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

		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		if (beanFactory != null) {
			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
				//设置beanFactory的依赖关系
				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
			}
			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
				//设置设置beanFactory的自动解析程序
				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
			}
		}

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
		//在Set集合中添加一系列内部的BeanDefinitionHolder.
		//BeanDefinitionHolder 主要持有 BeanDefinition的名称和别名
		//BeanDefinition描述bean实例的信息。如:bean的作用域、bean是否懒加载、bean的角色,bean的属性信息等。
		//bean的角色 role=0 用户使用 role=1内部bean,但是可以通过aware接口获取 role=2完全IOC容器内部。下面添加的bean全部是内部使用

		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			//添加ConfigurationClassPostProcessor 配置类后处理器
		}

		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			//添加AutowiredAnnotationBeanPostProcessor 自动注解bean后处理器
		}

		// 检查  JSR-250、JPA 支持 省略.......
		
		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
			//添加EventListenerMethodProcessor 事件方法处理器
		}

		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
			//添加DefaultEventListenerFactory 默认事件功工厂处理器
		}

		return beanDefs;
	}

registerAnnotationConfigProcessors注册注解配置处理器做了如下几件事:

  1. 根据传入的注册表registry获取beanFactory,这里的注册表其实就是spring的上下文实例,也就是IOC容器。beanFactory设置依赖关系和自动解析程序。
  2. 添加一系列处理器。设置角色role=2.全部是IOC容器内部使用。
    至此完成了注解bean定义读取器的初始化。

2.2 初始化ClassPathBeanDefinitionScanner

在这里插入图片描述
调用自身的构造器:

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
		this(registry, true);
	}

这是个门面方法:

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
		this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}

最终在构造器下实现:

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

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

		if (useDefaultFilters) {
		   //注册默认的过滤器
			registerDefaultFilters();
		}
		setEnvironment(environment);
		setResourceLoader(resourceLoader);
	}

注册默认过滤器:

    @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.
		}
	}
ClassPathScanningCandidateComponentProvider ClassPathBeanDefinitionScanner

ClassPathBeanDefinitionScanner继承ClassPathScanningCandidateComponentProvider。在注册过滤器的实现中。调用父类的方法registerDefaultFilters()。过滤的注解包括:@Component、@Repository、@Service、@Controller以及Java EE 6的ManagedBean和Named等注解。然后添加到List集合中。也就是说扫描器可以扫描那些注解配置。
这里包括添加

BeanFactory ListableBeanFactory HierarchicalBeanFactory ApplicationContext EnvironmentCapable ConfigurableApplicationContext AbstractApplicationContext GenericApplicationContext AnnotationConfigApplicationContext BeanDefinitionRegistry AliasRegistry

网站文章

  • npm - operation not permitted 解决方法

    npm - operation not permitted 解决方法

    2019独角兽企业重金招聘Python工程师标准&gt;&gt;&gt; ...

    2024-02-29 12:25:12
  • 最近的一次面试体验

    最近的一次面试体验

      上周2去一家中欧合资的公司参加高程面试,进公司给人的第一感觉,公司并不大,人数也不多在20-30人左右,老外有7-9个,公司主营业务是互联网电商.填写了资本资料后,递给了我一份英文笔试卷子,大概有34道题目。花了近40-50分钟做完题目,感觉老外的侧重点其实是我们平时并不太注意的基本知识,并不像我们一味推崇新技术.举个例子,其他的题目一一列举太耗时,随笔写写。View Code ...

    2024-02-29 12:25:05
  • 浪潮服务器加速计算系统,超强AI计算系统囊括浪潮人工智能服务器

    浪潮服务器加速计算系统,超强AI计算系统囊括浪潮人工智能服务器

    原标题:超强AI计算系统囊括浪潮人工智能服务器 浪潮云数据中心合作伙伴大会IPF2019在上海举行,会上,浪潮发布“浪潮元脑”,包含浪潮场景化人工智能基础设施,深度学习框架与工具和人工智能PaaS平台...

    2024-02-29 12:24:37
  • 简单Java前后端分离项目部署

    简单Java前后端分离项目部署

    返回导航页 返回导航页 简单部署,直接运行jar包 1、需要配置安全组 2、服务器需要防火墙开启端口 涉及到的相关命令解释: firewall-cmd --zone=public --add-port...

    2024-02-29 12:24:28
  • c语言2048小游戏报告,C语言写的2048小游戏

    基于&quot;基于C_语言的2048算法设计_颜冠鹏.pdf&quot;这一篇文献提供的思路在中国知网上能找到 就不贴具体内容了[摘 要] 针对2048的游戏规则,分析了该游戏的算法特点,对其相关的...

    2024-02-29 12:24:19
  • 03.leetcode-02.Add Two Numbers(链表)

    题目:02.Add Two NumbersYou are given twonon-emptylinked lists representing two non-negative integers. ...

    2024-02-29 12:23:50
  • maven SNAPSHOT

    MAVEN 有RELEASE版本 跟 SNAPSHOT版本机制: RELEASE版本机制 先检查本地仓库是否有依赖的包,如果没有就去中央仓库或远程私有仓库进行下载。如果本地仓库已经有的话,不论远程私有...

    2024-02-29 12:23:43
  • 如何打印菱形 (for循环)

    初学编程的时候(学到循环)遇到一个比较典型的问题:就是如何打印菱形,如下图:                 *               ***             *****           *******         *********           *******             *****    

    2024-02-29 12:23:36
  • Python入门自学进阶-Web框架——6、Django的ORM-多对多、admin应用

    Python入门自学进阶-Web框架——6、Django的ORM-多对多、admin应用

    对于多对多关系,如前面的Book和Author表,进行多对多关联插入时,有两种方法:第一种是前面介绍的通过book.author.add(*作者对象列表)来增加,这叫做正向查询插入,因为多对多字段定义...

    2024-02-29 12:23:13
  • cad打印本计算机未配置,CAD点打印为什么会警告提示无法使用此绘图仪配置

    cad打印本计算机未配置,CAD点打印为什么会警告提示无法使用此绘图仪配置

    有时我们想打印一张图纸,一点“打印”按钮,CAD就会弹出一个警告对话框,提示无法使用此绘图仪配置,如下图所示。为什么会出现这样的警告呢?通常在打开外单位的图纸时才会出现这样的问题,如果你对打印设置、页...

    2024-02-29 12:22:45