博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
<context:component-scan>详解
阅读量:5718 次
发布时间:2019-06-18

本文共 7571 字,大约阅读时间需要 25 分钟。

默认情况下,<context:component-scan>查找使用构造型(stereotype)注解所标注的类,如@Component(组件),@Service(服务),@Controller(控制器),@Repository(数据仓库)

我们具体看下<context:component-scan>的一些属性,以下是一个比较具体的<context:component-scan>配置

annotation-config="true"
name-generator="org.springframework.context.annotation.AnnotationBeanNameGenerator"
resource-pattern="**/*.class"
scope-resolver="org.springframework.context.annotation.AnnotationScopeMetadataResolver"
scoped-proxy="no"
use-default-filters="false"
>

以上配置注释已经很详细了,当然因为这些注释,你若是想复制去验证,你得删掉注释。我们具体再说明一下这些注释:

back-package:标识了<context:component-scan>元素所扫描的包,可以使用一些通配符进行配置

annotation-config:<context:component-scan>元素也完成了<context:annotation-config>元素的工作,开关就是这个属性,false则关闭属性注入注解功能

name-generator:这个属性指定你的构造型注解,注册为Bean的ID生成策略,这个生成器基于接口BeanNameGenerator实现generateBeanName方法,你可以自己写个类去自定义策略。这边,我们可不显示配置,它是默认使用org.springframework.context.annotation.AnnotationBeanNameGenerator生成器,也就是类名首字符小写的策略,如Performer类,它注册的Bean的ID为performer.并且可以自定义ID,如@Component("Joy").这边简单贴出这个默认生成器的实现。

public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {        if (definition instanceof AnnotatedBeanDefinition) {            String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);            if (StringUtils.hasText(beanName)) {                // Explicit bean name found.                return beanName;            }        }        // Fallback: generate a unique default bean name.        return buildDefaultBeanName(definition, registry);}

 

 Spring除了实现了AnnotationBeanNameGenerator生成器外,还有个org.springframework.beans.factory.support.DefaultBeanNameGenerator生成器,它为了防止Bean的ID重复,它的生成策略是类路径+分隔符+序号

 ,如com.wjx.betalot.performer.impl.Sonnet注册为Bean的ID是com.wjx.betalot.performer.impl.Sonnet#0,这个生成器不支持自定义ID,否则抛出异常。同样贴出代码,有兴趣的可以去看下。

public static String generateBeanName(            BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)            throws BeanDefinitionStoreException {        String generatedBeanName = definition.getBeanClassName();        if (generatedBeanName == null) {            if (definition.getParentName() != null) {                generatedBeanName = definition.getParentName() + "$child";            }            else if (definition.getFactoryBeanName() != null) {                generatedBeanName = definition.getFactoryBeanName() + "$created";            }        }        if (!StringUtils.hasText(generatedBeanName)) {            throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +                    "'class' nor 'parent' nor 'factory-bean' - can't generate bean name");        }        String id = generatedBeanName;        if (isInnerBean) {            // Inner bean: generate identity hashcode suffix.            id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);        }        else {            // Top-level bean: use plain class name.            // Increase counter until the id is unique.            int counter = -1;            while (counter == -1 || registry.containsBeanDefinition(id)) {                counter++;                id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;            }        }        return id;    }

 

resource-pattern:对资源进行筛选的正则表达式,这边是个大的范畴,具体细分在include-filter与exclude-filter中进行。

scoped-proxy: scope代理,有三个值选项,no(默认值),interfaces(接口代理),targetClass(类代理),那什么时候需要用到scope代理呢,举个例子,我们知道Bean的作用域scope有singleton,prototype,request,session,那有这么一种情况,当你把一个session或者request的Bean注入到singleton的Bean中时,因为singleton的Bean在容器启动时就会创建A,而session的Bean在用户访问时才会创建B,那么当A中要注入B时,有可能B还未创建,这个时候就会出问题,那么代理的时候来了,B如果是个接口,就用interfaces代理,是个类则用targetClass代理。这个例子出处:http://www.bubuko.com/infodetail-1434289.html。

scope-resolver:这个属性跟name-generator有点类似,它是基于接口ScopeMetadataResolver的,实现resolveScopeMetadata方法,目的是为了将@Scope(value="",proxyMode=ScopedProxyMode.NO,scopeName="")的配置解析成为一个ScopeMetadata对象,Spring这里也提供了两个实现,我们一起看下。首先是org.springframework.context.annotation.AnnotationScopeMetadataResolver中,

public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {        ScopeMetadata metadata = new ScopeMetadata();        if (definition instanceof AnnotatedBeanDefinition) {            AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;            AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(annDef.getMetadata(), this.scopeAnnotationType);            if (attributes != null) {                metadata.setScopeName(attributes.getAliasedString("value", this.scopeAnnotationType, definition.getSource()));                ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");                if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {                    proxyMode = this.defaultProxyMode;                }                metadata.setScopedProxyMode(proxyMode);            }        }        return metadata;    }

 

对比一下org.springframework.context.annotation.Jsr330ScopeMetadataResolver中的实现:

public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {        ScopeMetadata metadata = new ScopeMetadata();        metadata.setScopeName(BeanDefinition.SCOPE_PROTOTYPE);        if (definition instanceof AnnotatedBeanDefinition) {            AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;            Set
annTypes = annDef.getMetadata().getAnnotationTypes(); String found = null; for (String annType : annTypes) { Set
metaAnns = annDef.getMetadata().getMetaAnnotationTypes(annType); if (metaAnns.contains("javax.inject.Scope")) { if (found != null) { throw new IllegalStateException("Found ambiguous scope annotations on bean class [" + definition.getBeanClassName() + "]: " + found + ", " + annType); } found = annType; String scopeName = resolveScopeName(annType); if (scopeName == null) { throw new IllegalStateException( "Unsupported scope annotation - not mapped onto Spring scope name: " + annType); } metadata.setScopeName(scopeName); } } } return metadata; }

 

ps:scope-resolver与scoped-proxy只能配置一个,配置了scope-resolver后你要使用代理,可以配置@Scope总的proxyMode属性项

use-default-filters:是否使用默认的扫描过滤。

<context:include-filter> :用来告知哪些类需要注册成Spring Bean,使用type和expression属性一起协作来定义组件扫描策略。type有以下5种

过滤器类型 描述
annotation 过滤器扫描使用注解所标注的那些类,通过expression属性指定要扫描的注释
assignable 过滤器扫描派生于expression属性所指定类型的那些类
aspectj 过滤器扫描与expression属性所指定的AspectJ表达式所匹配的那些类
custom 使用自定义的org.springframework.core.type.TypeFliter实现类,该类由expression属性指定
regex 过滤器扫描类的名称与expression属性所指定正则表示式所匹配的那些类

 

 

 

 

 

 

 

要注意的是:若使用include-filter去定制扫描内容,要在use-default-filters="false"的情况下,不然会“失效”,被默认的过滤机制所覆盖

<context:exclude-filter>:与<context:include-filter> 相反,用来告知哪些类不需要注册成Spring Bean,同样注意的是:在use-default-filters="false"的情况下,exclude-filter是针对include-filter里的内容进行排除。

 

转载于:https://www.cnblogs.com/fightingcoding/p/component-scan.html

你可能感兴趣的文章
Javascript String类的属性及方法
查看>>
vim编辑器如何添加或删除多行注释
查看>>
[LeetCode] Merge Intervals
查看>>
2017 Multi-University Training Contest - Team 1 1003&&HDU 6035 Colorful Tree【树形dp】
查看>>
iOS开发-按钮的基本使用
查看>>
在QT和SDL搭建的框架中使用OPENGL在SDL窗口上进行绘图
查看>>
REST技术第三步 @BeanParam的使用
查看>>
模板 读入挂!
查看>>
SharePoint 读取 Site Columns 的数据并绑定到DropdownList
查看>>
Python中的对象行为与特殊方法(二)类型检查与抽象基类
查看>>
Ubuntu 16.04服务器版查看DHCP自动分配的IP、网关、DNS
查看>>
使用 axios 详解
查看>>
通信基站(dfs回溯,思维)
查看>>
nginx web加密访问
查看>>
iOS - Regex 正则表达式
查看>>
SYS_CONTEXT函数返回IP地址的一些误解
查看>>
第 68 章 Logical Volume Manager (LVM)
查看>>
膝盖中了一箭之康复篇-第八个月暨2月份目标总结
查看>>
CentOS 7 开放防火墙端口命令
查看>>
IPA提交APPStore问题记录(一)
查看>>