SpringBoot--003--理解@Component"派生性"原理

@Component派生性
  • spring可以扫描到,标注了@Component,以及使用了@Component注解的注解,可以是自定义注解。这种spring扫描到的注解,以及类似派生出的注解称为@Component的派生性。
原理
1 寻找处理器
  1. 在spring的xml文件中,根据Spring可扩展的XML编写扩展机制。元素XML Schema命名空间需要与其处理器建立映射关系,且配置在相对于classpath的规约资源/META-INF/spring.handlers中。
  2. 查找的Context处理器: 使用标签 < context:component-scan > 进行开启注解扫描,查询context的处理器为在这里插入图片描述
  3. 当扫描到< context:component-scan >注解时,调用ContextNamespaceHandler的init方法,注册了一些解析器,component-scan的解析器为ComponentScanBeanDefinitionParser
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());
}
  1. 既然能解析出@Component注解,以及“派生”注解,关键在于该类中。
2 注解解析
  1. 在解析标签时,调用BeanDefination解析器中的parse方法
public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
	private static final String BASE_PACKAGE_ATTRIBUTE = "base-package";
	String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
	@Override
	@Nullable
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		//解析元素的base-package属性,获取扫描的根路径
		String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
		basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
		//获取基本路径
		String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

		// Actually scan for bean definitions and register them.
		ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
		//在根路径下,扫描所有的注解,返回BeanDefinitionHolder信息
		Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
		registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

		return null;
	}
}
  1. 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) {
		//(真正获取beanDefinition的地方)获取bean的定义信息,来源在此,后续进行封装,转换
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
		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) {
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			if (candidate instanceof AnnotatedBeanDefinition) {
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			if (checkCandidate(beanName, candidate)) {
				//根据定义信息,创建definitionHodler对象
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				definitionHolder =
						AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				//bean定义增加,definitionHolder 
				beanDefinitions.add(definitionHolder);
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}
  1. ClassPathBeanDefinitionScanner.findCandidateComponents
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
	if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
		return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
	}
	else {
		//执行此处,该方法时父类的方法
		return scanCandidateComponents(basePackage);
	}
}
  1. ClassPathScanningCandidateComponentProvider.scanCandidateComponents
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
	//真正的扫描到的bean定义信息
	Set<BeanDefinition> candidates = new LinkedHashSet<>();
	try {
		//String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
		//此处将.换成/,最后的结果为  classpath*:com/learning/**/*.class
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + '/' + this.resourcePattern;
		//得到类资源集合,扫描到所有的类路径,如图1		
		Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
		boolean traceEnabled = logger.isTraceEnabled();
		boolean debugEnabled = logger.isDebugEnabled();
		for (Resource resource : resources) {
			if (traceEnabled) {
				logger.trace("Scanning " + resource);
			}
			//1. 如果资源可读,即可获取
			if (resource.isReadable()) {
				try {
					//2. 获取到元信息读取器,其中包括,类信息和注解信息,如图二
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
					//3. 执行判断是否符合 过滤器规则,函数内部用过滤器 对metadataReader 过滤
					if (isCandidateComponent(metadataReader)) {
						//4. 把符合条件的 类转换成 BeanDefinition
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setResource(resource);
						sbd.setSource(resource);
						//5. 再次判断 如果是实体类 返回true,如果是抽象类,但是抽象方法 被 @Lookup 注解注释返回true 
						if (isCandidateComponent(sbd)) {
							if (debugEnabled) {
								logger.debug("Identified candidate component class: " + resource);
							}
							//6. 将自定义注解的,Bean定义信息,加到bean定义信息集合中
							candidates.add(sbd);
						}
						...
					}
				}
				...
			}
			...
		}
	}
	...
	return candidates;
}

//判断是否是合理的元素,通过排除过滤器,和包含过滤器进行验证
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
	//属于排除的类型
	for (TypeFilter tf : this.excludeFilters) {
		if (tf.match(metadataReader, getMetadataReaderFactory())) {
			return false;
		}
	}
	//属于包含的类型
	for (TypeFilter tf : this.includeFilters) {
		//此方法会判断,tf是否与元信息匹配,比如,Component会匹配,Service,Controller,以及自定义注解
		if (tf.match(metadataReader, getMetadataReaderFactory())) {
			return isConditionMatch(metadataReader);
		}
	}
	return false;
}
  • 在父类初始化的时候,初始化了includeFilters的类型
public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) {
	if (useDefaultFilters) {
		registerDefaultFilters();
	}
	setEnvironment(environment);
	setResourceLoader(null);
}
//-------------registerDefaultFilters
protected void registerDefaultFilters() {
	//注解了Component类型
	this.includeFilters.add(new AnnotationTypeFilter(Component.class));
	...
}
  • 图1
    在这里插入图片描述
  • 图二
    在这里插入图片描述

自定义过滤规则–不依赖spring标签

  • 通过源码可以知晓,过滤的规则主要在include和exclude过滤器类,主要在于ClassPathBeanDefinitionScanner的scan方法,进行扫描包,获取标注的类。思路:通过后置处理器,将自定义的过滤规则加入,扫描自定义的包,即可
  • 代码
    • 后置处理器
    @Component
    public class CustomBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor {
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        	//1.定义扫描的执行类
            ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
            //2.注册过滤的类型
            TypeFilter includeFilter = new AnnotationTypeFilter(CustomComponent.class);
    		//3.增加包含的过滤类型
            scanner.addIncludeFilter(includeFilter);
            //4.添加扫描包
            String[] basePackages = {"com.book.firstspringboot.dto"};
            //5.扫描包中的类型,会自动注入到spring容器中
            scanner.scan(basePackages);
        }
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
        }
    }
    
    • 自定义标签
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface CustomComponent {
    
    }
    
    • controller类
    @RestController
    @RequestMapping("/test")
    public class FirstController {
    
        @Autowired
        private CustomDto dto;
    
        @RequestMapping("/t")
        public String print(){
            return dto.custom();
        }
    }
    
scan方法
public int scan(String... basePackages) {
	int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

	//真正扫描的方法
	doScan(basePackages);

	// Register annotation config processors, if necessary.
	if (this.includeAnnotationConfig) {
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

	return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值