spring源码---IOC:解析配置类(一)

目录

一,包扫描方式

二,refresh()


一,包扫描方式

第二种方式 包扫描方式(第一种是直接给一个bean的class对象,通过扫描类进行注解。)现在是给出MainConfig类的包,该包下面可能有几个配置类,入口:构造方法。

public AnnotationConfigApplicationContext(String... basePackages) {
   this();
   scan(basePackages);
   refresh();
}

  包扫描方式,如果让我实现,无非就是在第一种方式的基础上,增加了自己找到bean的过程,我们需要拿到路径,

扫描指定包路径及其子包下的注解类,为了使新添加的类被处理,必须手动调用refresh()方法刷新容器。
public void scan(String... basePackages) {
   this.scanner.scan(basePackages);
}

  可以看到,我们的scanner 包扫描类排上用场了。ClassPathBeanDefinitionScanner类

//调用类路径Bean 定义扫描器入口方法。
	public int scan(String... basePackages) {
		//获取容器 中已经 注册的bean的个数。
		int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
		//启动扫描器 扫描 给定包。   ---【深入】----
		doScan(basePackages);
		//注册注解配置 (Annotation config )处理器。
		// Register annotation config processors, if necessary.
		if (this.includeAnnotationConfig) {
			AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
		}
		//返回注册的bean的个数。
		return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
	}

  这里也是一个入口,真正开始扫描的当然是doScan()这里方法,而ClassPathBeanDefinitionScanner这个类,也可以整体进行一下研究,意义还是大。(这里为什么要获取已经注册的bean,或许是为了在扫描的时候,避免重复加载吧)

    doSan()方法:这里或许就如同doRegister()一样,哈哈哈。

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
   //结果容器准备好
   Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
   for (String basePackage : basePackages) { //开始遍历 包路径,一般就是一个
      Set<BeanDefinition> candidates = findCandidateComponents(basePackage); //找到符合条件的bean定义
      //遍历扫描到的bean
      for (BeanDefinition candidate : candidates) {
         ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
         candidate.setScope(scopeMetadata.getScopeName());
         String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
         if (candidate instanceof AbstractBeanDefinition) { //抽象bean
            postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
         }
         if (candidate instanceof AnnotatedBeanDefinition) { //注解bean
            AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
         }
         if (checkCandidate(beanName, candidate)) { //封装bean
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
            definitionHolder =
                  AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            beanDefinitions.add(definitionHolder); //保存
            registerBeanDefinition(definitionHolder, this.registry); //注册Bean
         }
      }
   }
   return beanDefinitions;
}

分析一下:

    1.创建存放 封装bean 的集合:Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();

    2.扫描路径,获得beanDefinition:Set<BeanDefinition> candidates = findCandidateComponents(basePackage);

    3.遍历扫描到的beanDefinition:这里就如同doRegister对bean坐的操作一样。所以我们重点放在第二部,解析路径。

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
   if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
      return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
   }
   else {
      return scanCandidateComponents(basePackage);
   }
}

    这里判断了个什么鬼,表示看不懂,反正走add...()方法

private Set<BeanDefinition> addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) {
		//创建扫描到的类集合
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
			Set<String> types = new HashSet<>();
			for (TypeFilter filter : this.includeFilters) {
				String stereotype = extractStereotype(filter);
				types.addAll(index.getCandidateTypes(basePackage, stereotype));
			for (String type : types) {
				//为指定资源获取 元数据 读取器,元数据读取器 通过汇编(ASM) 读取资源的元信息。
				MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
				//如果扫描到的类符合 容器配置的过滤规则。
				if (isCandidateComponent(metadataReader)) {   //--这里【深入】一下
					//通过汇编(ASM) 读取资源字节码中的bean定义的元信息。
					ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                    if (isCandidateComponent(sbd)) {
						candidates.add(sbd);
					}
					。。。。。
		return candidates;
	}

      (注意)这里有一个概念,也是bean生命周期中的,TypeFilter,bean的过滤器,他可以设置哪些bean需要注册(为什么需要这个,比如说,不同的环境,开发,测试,生成,会使用不同的配置,不同的bean,不同的操作系统,不同的浏览器,根据环境而定,所以这里需要进行拦截,在一些环境下,有些bean是不需要启动的,还比如说,多个扫描,第一次扫描不用启动Controller,让mvc的扫描器去启动Controller,这些都需要进行拦截。并且可以自定义拦截器。

       这里就是通过元数据,然后返回了sbd这个封装的bean,直接把这个bean存进了集合里面,

   细节观看:

    1.basePackage如何转换的: 通过路径,返回了type。这里说了是一个String集合。(大胆猜测,这里应该是拿的每一个类的路径,但是为什么取名字叫type)

	public Set<String> getCandidateTypes(String basePackage, String stereotype) {
		List<Entry> candidates = this.index.get(stereotype);
		if (candidates != null) {
			return candidates.parallelStream()
					.filter(t -> t.match(basePackage))
					.map(t -> t.type)
					.collect(Collectors.toSet());
		}
		return Collections.emptySet();
	}

   2.通过这个字符串,生成了元素据MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);

     看见这个参数名字没有  className 上一步的type没有猜错吧。。

public MetadataReader getMetadataReader(String className) throws IOException {
		try {
			//className是 .xx.xx的形式,这里要转换成为pc file路径形式。
			String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
					ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
			//通过路径获得资源。
			Resource resource = this.resourceLoader.getResource(resourcePath);
			//看来这个方法又是一个入口。
			return getMetadataReader(resource);
		}
}
//----------------------------
	public MetadataReader getMetadataReader(Resource resource) throws IOException {
		return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
	}

   这里资源装载器又排上了用场,这里找到的应该是一个class文件吧。。通过resource 返回了一个类,这个类应该是封装了resource才对。

final class SimpleMetadataReader implements MetadataReader {
	private final Resource resource;  //在这里。
	private final ClassMetadata classMetadata; //元数据出现了
	private final AnnotationMetadata annotationMetadata; //还有注解的元数据,
}

到了这里,应该说就和 直接register(class)一样了吧,什么数据都准备好了。

回到ClassPathBeanDefinitionScanner类中,遍历beanDefinition,将其封装成为。。。Holder,进行register()后面的就是老套路了。

二,refresh()

        不管是直接给出配置类,还是给出扫描路径,最后都会走refresh()方法,它和xml方式都一样,还是refresh()方法,但是AbstractApplicationContext类使用委派模式,注解模式和xml模式实现的方法是不同的,现在我们看源码分析:

 2.2 obtainFreshBeanFactory()

     注解方式实现的此步骤比较简单,直接从GenericApplicationContext中获取beanFactory并返回。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   //第二层类
   refreshBeanFactory();
   //返回DefaultListableBeanFactory 也由第二层实现,获得上 方法初始化的结果。
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   return beanFactory;
}

    refreshBeanFactory()方法就是第二层子类的方法,在annotation中,它只有两个父类,这里显示第二层,那么就是GenericApplicationContext类:

protected final void refreshBeanFactory() throws IllegalStateException {
   this.beanFactory.setSerializationId(getId());
}

    设置了序列化id,其他就没有了,没有xml方式的创建DefaultBeanFactory的过程,因为GenericApplicationContext在无参构造方法中就已经初始化了beanFactory,并且还注入了默认的6个bean和我们自定义的配置bean。

2.3 prepareBeanFactory()

 该方法, 在后面的refresh()章节中还会讲过,是xml方式的,这个方法是通用的,重点是注册了两个后置处理器ApplicationContextAwareProcessor处理器和ApplicationListenerDetector处理器

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // Tell the internal bean factory to use the context's class loader etc.
   beanFactory.setBeanClassLoader(getClassLoader());
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

   // Configure the bean factory with context callbacks. 添加后置处理器
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //第一个后置处理器
   //忽略的接口
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
.....
   //依赖对象的设置
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); //第二个后置处理器

   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   // Register default environment beans. 注册默认 环境 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());
   }
}

效果:

2.4 postProcessBeanFactory()

在spring基于注解启动或者xml初始化的时候,这个方法是空的,未实现。

而使用springboot启动,会调用AnnotationConfigServletWebServerApplicationContext的方法

	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 调用弗雷的后置处理工厂bean
		super.postProcessBeanFactory(beanFactory);
		if (this.basePackages != null && this.basePackages.length > 0) {
			this.scanner.scan(this.basePackages);
		}
		if (!this.annotatedClasses.isEmpty()) {
			this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
		}
	}
	@Override
	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(ServletContextAware.class);
        // 注册作用域
		registerWebApplicationScopes();
	}

给beanFactory注册一个后置处理器之后,会调用registerWebApplicationScopes(),注册作用范围:

	public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
			@Nullable ServletContext sc) {
        // request
		beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
        // session
		beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
		if (sc != null) {
			ServletContextScope appScope = new ServletContextScope(sc);
            // application
			beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
			// Register as ServletContext attribute, for ContextCleanupListener to detect it.
			sc.setAttribute(ServletContextScope.class.getName(), appScope);
		}
        // 注册解析依赖
		beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
		beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
		beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
		beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
		if (jsfPresent) {
			FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
		}
	}

2.5  invokeBeanFactoryPostProcessors()

    (重点)调用后置处理器 ,首先调用PostProcessorRegistrationDelegate后置处理器注册代理类,它是一个独立的类,没有继承关系。

invoke---调用

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()));
   }
}

// 获取后置处理器列表
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
   return this.beanFactoryPostProcessors;
}

重点是第一个方法,调用后置处理器的时候,开始进行bean的解析。!

注意beanFactoryPostProcessors字段还是空的,因为这里调用的是AbstractApplicationContext容器的属性字段,在上一步注册的beanPostProcessors是BeanFactory的属性字段。

跳转到代理类:PostProcessorRegisterationDelegate类中,该类中的代码方法很长,我们看核心部分:

public static void invokeBeanFactoryPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
   Set<String> processedBeans = new HashSet<>();

   if (beanFactory instanceof BeanDefinitionRegistry) {
      BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
      //定义两个处理器集合,两个类型其实是继承关系  regular---常规的
      List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
      List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
      //执行 扩展的BeanFactoryPostProcessor, 因为可以 自定义扩展(用户自定义的后置处理器,实现BeanDefinitionRegistryPostProcessor接口) 
      for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            .... 因为没有自定义,所有省略了
      }
        //存放后置处理器 列表
      List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

      【重点】 此处获得了 后置处理器名字 从beanFactory中
      String[] postProcessorNames =  // 获取 下面这个类型的 bean,然后进行排序
            beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
         if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//获得实例 ,并保存
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
         }
      }
      sortPostProcessors(currentRegistryProcessors, beanFactory);
      registryProcessors.addAll(currentRegistryProcessors);
  【重点】
      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
      currentRegistryProcessors.clear(); //清0,下一段不重复使用
     

分开步骤分析:

1.找到后置处理器

beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

可见这个接口,只有唯一实现类,所以非他莫属

具体的实现在DefaultListableBeanFactory类中,也就是容器(现在容器中存放了几个初始的beanDefinition)中进行查找:

public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
   if (!isConfigurationFrozen() || type == null || !allowEagerInit) { //不正常情况
      return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
   }
   Map<Class<?>, String[]> cache =
         (includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
   String[] resolvedBeanNames = cache.get(type); //缓存中直接获取
   if (resolvedBeanNames != null) {
      return resolvedBeanNames;
   } //缓存未命中
   resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
   if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
      cache.put(type, resolvedBeanNames);
   }
   return resolvedBeanNames;
}

返回结果:

 内部处理Configuration注解的处理器

然后会使用beanFactory.getBean()获取该bean的实例,这个时候由于里面的依赖,所以会实例化很多个bean。

2.执行后置处理器方法

invokeBeanDefinitionRegistryPostProcessors()

private static void invokeBeanDefinitionRegistryPostProcessors(
      Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
   for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
      postProcessor.postProcessBeanDefinitionRegistry(registry); //执行  重点ConfigurationClassPostProcessor类
   }
}

传入的自然就是ConfigurationClassPostProcessor类,进行后置处理,调用的是处理器的方法,

具体解析:请看下一节的讲解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值