component-scan 注册bean原理解析

我们知道在可以在Spring配置文件中配置 <bean>向Spring容器中注册Bean
实际开发中我们有很多Bean需要注入,需要一种更高效的方式来注入Bean,就是通过扫描指定包路径

 <context:component-scan base-package="com.dlh.spring.context" />

在配置文件中配置这个就能扫描指定包路径下的类将其注册到容器当中


ContextNamespaceHandler:

context 节点对应的命名空间处理类是ContextNamespaceHandler,我们知道Spring 解析配置文件需要用到NamespaceHandler实现类时先调用init(一般都是注册一些特定dom元素的解析器)方法,再调用parse方法,比如component-scan 就会用到ComponentScanBeanDefinitionParser来解析<context:component-scan base-package="com.dlh.spring.context" />

public class ContextNamespaceHandler extends NamespaceHandlerSupport {
	@Override
	public void init() {
		registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
		registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
		registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
		registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
	}

}
// 执行完init方法后 再调用pares方法 这个在子类NamespaceHandlerSupport定义,根据Element拿到一个解析器,再调用这个具体的解析器向容器中注册Bean
public BeanDefinition parse(Element element, ParserContext parserContext) {
		BeanDefinitionParser parser = findParserForElement(element, parserContext);
		return (parser != null ? parser.parse(element, parserContext) : null);
}

ComponentScanBeanDefinitionParser:

parse方法

parse实现注册bean的功能,主要有下面几个流程

  1. 读取扫描路径(base-package属性)
  2. 创建ClassPathBeanDefinitionScanner对象
  3. 调用ClassPathBeanDefinitionScanner doScan方法扫描包路径下类注册到Spring容器
  4. 注入处理注解相关的bean后处理器
  5. 发布CompositeComponentDefinition注册事件

创建ClassPathBeanDefinitionScanner的流程

ClassPathBeanDefinitionScanner 用来扫描包路径向容器注册bean,我们来看看它的继承体系,和属性
解析component-scan 标签的属性值来给自己的属性赋值,

如果我们向知道component-scan标签具体有哪些属性怎么办呢
可以参考http://www.springframework.org/schema/context
在这里插入图片描述
也可已直接在工具里面编辑,IDEA提示功能还是很强大的
在这里插入图片描述

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) {
			/**
			 * 扫描到的类
			 * 生成一组 ScannedGenericBeanDefinition
			 */
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				// 主要包括bean的scope属性(默认单例)以及代理策略(不需要代理,JDK动态代理、CGLIB)
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				// 扫描定义的时 ScannedGenericBeanDefinition
				if (candidate instanceof AbstractBeanDefinition) {
					// 也继承了 AbstractBeanDefinition 设置是否自动装配
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				/**
				 * 上一步扫描出来的ScannedGenericBeanDefinition 是注解bean
				 */
				if (candidate instanceof AnnotatedBeanDefinition) {
					/**
					 * 拿到常用注解信息放到 Bean定义里面
					 */
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					/**
					 * 根据scopeMetadata 属性判断是否重新生成 beanDefinitions
					 * 重新生成的beanDefinitions class 是 ScopedProxyFactoryBean gebean的时候拿到的是代理过的对象
					 */
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					/**
					 * 注册bean到容器
					 */
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

大概分下面几个流程

  1. ClassPath 包扫描路径下所有Class文件,将复合条件的Class包装成ScannedGenericBeanDefinition
	protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
		for (TypeFilter tf : this.excludeFilters) {//@1 ClassPathBeanDefinitionScanner 构造时,excludeFilters未传入值
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return false;
			}
		}
		/**
		* includeFilters 在构建ScannedGenericBeanDefinition时调用了registerDefaultFilters
		* 是AnnotationTypeFilter 
		* 当前类是否匹配AnnotationTypeFilter条件 是在父类 AbstractTypeHierarchyTraversingFilter match方法里面判断 当前类中有被 Component注解就满足条件
	    */
		for (TypeFilter tf : this.includeFilters) {
			
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				// true 为复合条件的可以注册的bean
				return isConditionMatch(metadataReader);
			}
		}
		return false;
	}

满足上面Filter条件后 还有一个isConditionMatch判断,这里是判断类上面的条件注解,定位到一个shouldSkip方法,这个方法为true的话,当前类就不能添加到spring容器

	public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
	 	/**
	 	注解信息为空 或者不包含条件注解不能Skip ,返回false也就是可以注册到Spring 容器
		 */
		if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
			return false;
		}
      	/**
	 	 解析component-scan 标签,调用shouldSkip phase 传的是null,先进入这个条件判断
		 */
		if (phase == null) {
			if (metadata instanceof AnnotationMetadata &&
					ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
				/**
				 *    candidateIndicators 添加了Component ComponentScan Import  ImportResource 注解
				 * 	  isConfigurationCandidate 的判断逻辑是类有Component ComponentScan Import  ImportResource 注解,
				 *    或者类中的方法有@Bean注解返回true
				 * 
				 */
				return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
			}
			return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
		}

		List<Condition> conditions = new ArrayList<>();
		for (String[] conditionClasses : getConditionClasses(metadata)) {
			for (String conditionClass : conditionClasses) {
				Condition condition = getCondition(conditionClass, this.context.getClassLoader());
				conditions.add(condition);
			}
		}

		AnnotationAwareOrderComparator.sort(conditions);
        /**
        * 拿到条件注解
        **/
		for (Condition condition : conditions) {
			ConfigurationPhase requiredPhase = null;
			if (condition instanceof ConfigurationCondition) {
				requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
			}

		      /**
				 *  &&前面的条件是requiredPhase 为null 或者条件注解为ConfigurationCondition类型ConfigurationPhase等于入参
				 * 	ConfigurationCondition要业务实现Spring中没提供对应的实现类,所以这里&&前面的条件是true
				 *  !condition.matches(this.context, metadata) 就是判断是否匹配条件注解,不匹配进入这个if判断返回true,也就是不注册到Spring容器
				 */
			if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
				return true;
			}
		}

		return false;
	}
  1. 添加到容器的Bean设置ScopeMetadata属性,BeanDefinition的默认属性,Bean相关的注解属性比如Lazy 添加到bean定义
  2. 根据Bean的Scope属性判断是否要添加一个Class类型是ScopedProxyFactoryBean(FactoryBeanl 通过getObject方法获取实例,实例时一个代理类)的Bean到容器
    这里如果筛选处理的类有Scope注解会调用ScopedProxyUtils createScopedProxy方法重新生成一个BeanDefinitionHolder 重新生成一个BeanDefinitionHolder
static BeanDefinitionHolder applyScopedProxyMode(
			ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {

		ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
		if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
			return definition;
		}
		boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
		// 如果是INTERFACES 或者TARGET_CLASS 调用ScopedProxyUtils createScopedProxy方法重新生成一个BeanDefinitionHolder
		return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
	}

查看createScopedProxy可以看到里面重新创建了一个RootBeanDefinition, beanClass 是ScopedProxyFactoryBean
在这里插入图片描述
实现了FactoryBean接口 ,也就是我们调用getBean去获取实例的时候,调用的的是ScopedProxyFactoryBean的getObject方法

public Object getObject() {
		if (this.proxy == null) {
			throw new FactoryBeanNotInitializedException();
		}
		return this.proxy;
	}
public void setBeanFactory(BeanFactory beanFactory) {
		if (!(beanFactory instanceof ConfigurableBeanFactory)) {
			throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);
		}
		ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;

		this.scopedTargetSource.setBeanFactory(beanFactory);

		ProxyFactory pf = new ProxyFactory();
		pf.copyFrom(this);
		pf.setTargetSource(this.scopedTargetSource);

		Assert.notNull(this.targetBeanName, "Property 'targetBeanName' is required");
		Class<?> beanType = beanFactory.getType(this.targetBeanName);
		if (beanType == null) {
			throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName +
					"': Target type could not be determined at the time of proxy creation.");
		}
		if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {
			pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));
		}

		// Add an introduction that implements only the methods on ScopedObject.
		ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
		pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));

		// Add the AopInfrastructureBean marker to indicate that the scoped proxy
		// itself is not subject to auto-proxying! Only its target bean is.
		pf.addInterface(AopInfrastructureBean.class);

		/**
		 * jdk 或者cglib 代理
		 * JdkDynamicAopProxy
		 * ObjenesisCglibAopProxy
		 */
		this.proxy = pf.getProxy(cbf.getBeanClassLoader());
	}

这里的proxy 对象在setBeanFactory 已经生成了,是一个代理类 JdkDynamicAopProxy 或者ObjenesisCglibAopProxy
JdkDynamicAopProxy 实现了InvocationHandler接口所有的调用都会走到invoke方法里面
invoke方法里面调用AdvisedSupport 类的getInterceptorsAndDynamicInterceptionAdvice 方法拿到了MethodInterceptor列表 ,包装成ReflectiveMethodInvocation执行

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

在这里插入图片描述
这里的AdvisedSupport 是 ProxyFactory
6. registerBeanDefinition 将BeanDefinition注册到容器

registerBeanDefinition(definitionHolder, this.registry);

注册处理注解相关的后处理器

如果 component-scan节点的annotation-config 属性为true,则向Spring容器中 添加几个处理注解相关的后处理器Bean(未配置annotation-config 也默认添加)

	Set<BeanDefinitionHolder> processorDefinitions =
					AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
后处理器Bean描述
ConfigurationClassPostProcessor容器后处理器Bean 解析有Configuration注解的类
AutowiredAnnotationBeanPostProcessorBean后处理器 处理 Autowired Value注解
CommonAnnotationBeanPostProcessor处理Resource注解
PersistenceAnnotationBeanPostProcessor处理JPA相关注解的后处理器
EventListenerMethodProcessor容器后处理器Bean 主要是对标注了 @EventListener 的方法进行解析, 然后转换为一个 ApplicationListener
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值