Spring4.3.x 浅析xml配置的解析过程(8)——解析context命名空间之component-scan标签

概述


Spring context命名空间有property-placeholder、property-override、annotation-config、component-scan、load-time-weaver、spring-configured、mbean-export和mbean-server 8个标签。

property-placeholder和property-override标签的解析见property-placeholder和property-override标签的解析,annotation-config标签的解析见解析context命名空间之annotation-config标签。这一节来探讨component-scan标签的解析与用途。

解析component-scan标签


component-scan标签拥有同annotation-config标签一样的作用,但它比annotation-config标签更强大。annotation-config标签主要作用是注册后处理来对已创建的BeanDefintion对象和实例化的bean做加工,component-scan标签作用不仅于此,还可以把特定包下被指定注解类标注的类对象封装成BeanDefinition对象并注册到BeanDefinitionRegistry对象中,这样大大简化了xml文件的内容。

component-scan标签的解析器类为ComponentScanBeanDefinitionParser类,它直接实现了BeanDefinitionParser接口,下面是它实现的parse方法的源代码。

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {

        String basePackage = element.getAttribute("base-package");
        // 处理base-package属性值中被“${”、“}”包围的变量
        // 比如,base-package="${package}",如果上下文环境对象中有一个Properties对象的key为package
        // ->那么,base-package的值就为这个key对应的value值
        basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
        // 如果有多个根包需要扫描,那么以“,; \t\n”中的一个隔开
        String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,",; \t\n");

        // Actually scan for bean definitions and register them.
        // 创建ClassPathBeanDefinitionScanner对象,这个对象用于扫描base-package指定的包下面的类对象
        // ->并把匹配的类对象使用BeanDefinition对象封装,然后注册到BeanDefinitionRegistry中
        ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
        Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);

        // 注册ComponentDefinition和注解配置处理器(和annotation-config标签的一样)
        registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

        return null;
    }

ComponentScanBeanDefinitionParser的parser方法,首先创建并初始化ClassPathBeanDefinitionScanner对象;然后使用前面scanner对象扫描指定包下匹配的类对象并注册相应BeanDefinition对象;最后调用registerComponents方法,如果属性annotation-config的值为true,则同annotation-config标签一样会注册处理注解配置的各种后处理器。我们先看看最后一步中的registerComponents方法,后面我们在来详细探讨spring如何扫描和匹配包下的类对象。

    protected void registerComponents(
            XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {

        Object source = readerContext.extractSource(element);
        CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);

        for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
            compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
        }

        // Register annotation config processors, if necessary.
        boolean annotationConfig = true;
        if (element.hasAttribute("annotation-config")) {
            annotationConfig = Boolean.valueOf(element.getAttribute("annotation-config"));
        }
        if (annotationConfig) {
            Set<BeanDefinitionHolder> processorDefinitions =
                    AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
            for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
                compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
            }
        }

        readerContext.fireComponentRegistered(compositeDef);
    }

registerComponents方法代码很简单,它主要是拿去component-scan标签的annotation-config属性值,这个属性值默认为true的,如果annotation-config值为true,则注册注解配置的各个处理器,这个注册过程在上一节——“解析annotation-config标签”中已经探讨了,这里就不用再说了。

这一节我们详细讨论spring如何使用component-scan标签来扫描和匹配包下的类对象。

(1)创建并初始化ClassPathBeanDefinitionScanner对象
ComponentScanBeanDefinitionParser的parser方法调用configureScanner(ParserContext parserContext, Element element)方法来创建初始化并返回一个ClassPathBeanDefinitionScanner对象,这个方法的源码如下。

    protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {

        // 设置是否自动检测被@Component、@Repository、@Service或者@Controller注解标注的类
        // 默认为true。如果为false,那么上面4个注解将没有作用,因此一般都不会设置这个属性
        boolean useDefaultFilters = true;
        if (element.hasAttribute("use-default-filters")) {
            useDefaultFilters = Boolean.valueOf(element.getAttribute("use-default-filters"));
        }

        // 把注册BeanDefinition的任务委托给scanner
        ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
        scanner.setResourceLoader(parserContext.getReaderContext().getResourceLoader());
        scanner.setEnvironment(parserContext.getReaderContext().getEnvironment());
        // 让scanner持有component-scan标签的父节点<beans>的属性默认值
        scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
        scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());

        // 设置资源匹配模式,默认为**/*.class
        if (element.hasAttribute("resource-pattern")) {
            scanner.setResourcePattern(element.getAttribute("resource-pattern"));
        }

        try {
            // 设置Bean名称生成器
            parseBeanNameGenerator(element, scanner);
        } catch (Exception ex) {
            parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
        }

        try {
            // 设置作用域
            parseScope(element, scanner);
        } catch (Exception ex) {
            parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
        }

        // 设置过滤器,即用于指定哪些类需要被处理,哪些类需要被忽略
        parseTypeFilters(element, scanner, parserContext);

        return scanner;
    }

configureScanner方法有4步,第一步是调用createScanner方法来创建一个ClassPathBeanDefinitionScanner 对象,并使用ParserContext对象来初始化它;第二步是调用parseBeanNameGenerator方法;第三步是调用parseScope方法,第四步是调用parseTypeFilters方法。下面我们分别介绍这4个方法。

1)调用createScanner方法创建ClassPathBeanDefinitionScanner 对象,代码如下。

    /**
    * 创建并返回ClassPathBeanDefinitionScanner对象
    **/
    protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
        return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters);
    }

2)调用parseBeanNameGenerator方法设置Bean名称生成器

    protected void parseBeanNameGenerator(Element element, ClassPathBeanDefinitionScanner scanner) {
        if (element.hasAttribute("name-generator")) {
            // 生成一个BeanNameGenerator对象
            BeanNameGenerator beanNameGenerator = (BeanNameGenerator) instantiateUserDefinedStrategy(
                    element.getAttribute("name-generator"), BeanNameGenerator.class,
                    scanner.getResourceLoader().getClassLoader());
            scanner.setBeanNameGenerator(beanNameGenerator);
        }
    }

parseBeanNameGenerator为scanner对象设置一个BeanNameGenerator接口对象。spring提供了两个这样的对象,其一是AnnotationBeanNameGenerator,它被用于获取被@Component等注解的类对象的bean名称。其二是DefaultBeanNameGenerator,它被用于获取一般bean的名称。

生成BeanNameGenerator对象调用了ClassPathBeanDefinitionScanner类的私有方法instantiateUserDefinedStrategy,这个方法用于实例化一个指定类型的对象,源码如下。

    /**
    * 根据指定的class名称实例化一个对象,这个对象必须为指定的strategyType类型。
    **/
    private Object instantiateUserDefinedStrategy(String className, Class<?> strategyType, ClassLoader classLoader) {
        Object result;
        try {
            result = classLoader.loadClass(className).newInstance();
        } catch (ClassNotFoundException ex) {
            throw new IllegalArgumentException("Class [" + className + "] for strategy [" +
                    strategyType.getName() + "] not found", ex);
        } catch (Exception ex) {
            throw new IllegalArgumentException("Unable to instantiate class [" + className + "] for strategy [" +
                    strategyType.getName() + "]: a zero-argument constructor is required", ex);
        }

        if (!strategyType.isAssignableFrom(result.getClass())) {
            throw new IllegalArgumentException("Provided class name must be an implementation of " + strategyType);
        }
        return result;
    }

3)调用parseScope方法设置作用域解析器或者作用域的默认代理模式

    protected void parseScope(Element element, ClassPathBeanDefinitionScanner scanner) {
        // 如果scope-resolver有值,则注册ScopeMetadataResolver
        if (element.hasAttribute("scope-resolver")) {
            if (element.hasAttribute("scoped-proxy")) {
                throw new IllegalArgumentException(
                        "Cannot define both 'scope-resolver' and 'scoped-proxy' on <component-scan> tag");
            }
            ScopeMetadataResolver scopeMetadataResolver = (ScopeMetadataResolver) instantiateUserDefinedStrategy(
                    element.getAttribute("scope-resolver"), ScopeMetadataResolver.class,
                    scanner.getResourceLoader().getClassLoader());
            scanner.setScopeMetadataResolver(scopeMetadataResolver);
        }

        // 设置作用域的默认代理模式ScopedProxyMode
        if (element.hasAttribute("scoped-proxy")) {
            String mode = element.getAttribute("scoped-proxy");
            if ("targetClass".equals(mode)) {
                scanner.setScopedProxyMode(ScopedProxyMode.TARGET_CLASS);
            } else if ("interfaces".equals(mode)) {
                scanner.setScopedProxyMode(ScopedProxyMode.INTERFACES);
            } else if ("no".equals(mode)) {
                scanner.setScopedProxyMode(ScopedProxyMode.NO);
            } else {
                throw new IllegalArgumentException("scoped-proxy only supports 'no', 'interfaces' and 'targetClass'");
            }
        }
    }

注:scope-resolver和scoped-proxy不能同时定义。

4)调用parseTypeFilters方法设置类型过滤器
parseTypeFilters方法主要是用来component-scan标签的include-filter和exclude-filter子节点。include-filter标签用来表示必须包含的类,不管这个类是否被默认的注解类标注。exclude-filter标签用来表示扫描时必须忽略的类,即使这个类被默认的注解标注了。但include-filter和exclude-filter两个元素不能共存。

    protected void parseTypeFilters(Element element, ClassPathBeanDefinitionScanner scanner, ParserContext parserContext) {
        // 解析exclude和include过滤器元素
        ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();
        NodeList nodeList = element.getChildNodes();
        // 遍历component-scan标签下的子节点
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                String localName = parserContext.getDelegate().getLocalName(node);
                try {
                    if ("include-filter".equals(localName)) {
                        // 解析include元素
                        TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
                        scanner.addIncludeFilter(typeFilter);
                    } else if ("exclude-filter".equals(localName)) {
                        解析exclude元素
                        TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
                        scanner.addExcludeFilter(typeFilter);
                    }
                } catch (Exception ex) {
                    parserContext.getReaderContext().error(
                            ex.getMessage(), parserContext.extractSource(element), ex.getCause());
                }
            }
        }
    }

parseTypeFilters方法首先判断区分出include-filter和exclude-filter标签,然后调用createTypeFilter方法来解析他们并返回TypeFilter,scanner把他们的指代的TypeFilter对象保存到它的includeFilters和excludeFilters列表中。

    /**
    * 解析component-scan标签的include-filter和exclude-filter子节点,并返回TypeFilter对象
    **/
    protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader, ParserContext parserContext) {
        String filterType = element.getAttribute("type");
        String expression = element.getAttribute("expression");
        expression = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(expression);
        try {
            if ("annotation".equals(filterType)) {
                // 指定过滤的注解。expression=类全名称
                return new AnnotationTypeFilter((Class<Annotation>) classLoader.loadClass(expression));
            } else if ("assignable".equals(filterType)) {
                // 指定过滤的类,它的子类或者实现类也包括。expression=类全名称
                return new AssignableTypeFilter(classLoader.loadClass(expression));
            } else if ("aspectj".equals(filterType)) {
                // 指定aspectj表达式来过滤类。expression=aspectj表达式字符串
                return new AspectJTypeFilter(expression, classLoader);
            } else if ("regex".equals(filterType)) {
                // 通过指定的正则表达式来过滤类。expression=正则表达式字符串
                return new RegexPatternTypeFilter(Pattern.compile(expression));
            } else if ("custom".equals(filterType)) {
                // 用户自定义过滤器类型
                Class<?> filterClass = classLoader.loadClass(expression);
                if (!TypeFilter.class.isAssignableFrom(filterClass)) {
                    throw new IllegalArgumentException(
                            "Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression);
                }
                return (TypeFilter) BeanUtils.instantiateClass(filterClass);
            } else {
                throw new IllegalArgumentException("Unsupported filter type: " + filterType);
            }
        } catch (ClassNotFoundException ex) {
            throw new FatalBeanException("Type filter class not found: " + expression, ex);
        }
    }

(2)使用ClassPathBeanDefinitionScanner对象的doScan(String… basePackages)方法开始扫描包,这个方法的源码如下。

    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
        // 遍历指定的包
        for (String basePackage : basePackages) {
            // 获取包下的所有候选BeanDefinition对象
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            // 遍历所有候选BeanDefinition对象
            for (BeanDefinition candidate : candidates) {
                // 获取一个ScopeMetadata对象,默认为AnnotationScopeMetadataResolver
                // 如果目标类未被@Scope注解,则返回一个默认的ScopeMetadata
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());

                // 使用bean名称生成器生成bean名称,默认生成器为AnnotationBeanNameGenerator
                // 首先是以注解的value为bean名称,如果注解的value没有值,则使用默认的名称
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                if (candidate instanceof AbstractBeanDefinition) {
                    // 进一步处理BeanDefinition对象,比如,bean是否可以被用于自动注入的备选bean
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                if (candidate instanceof AnnotatedBeanDefinition) {
                    // 处理定义在目标类上的注解,包括@Lazy, @Primary, @DependsOn, @Role, @Description
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
                // 检查beanName是否已经存在BeanDefinitionRegistry中存在
                if (checkCandidate(beanName, candidate)) {
                    // beanName还没被使用过
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    // 如果有必要,则创建作用域代理
                    // 如果创建了代理,则返回表示代理对象的BeanDefinitionHolder
                    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    // 注册BeanDefinitionHolder对象
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        return beanDefinitions;
    }

关于doScan方法所调用的方法,我只探讨其中的三个,其一是ClassPathBeanDefinitionScanner的findCandidateComponents方法;其二是AnnotationConfigUtils的processCommonDefinitionAnnotations静态方法;其三是AnnotationConfigUtils的applyScopedProxyMode静态方法。

1) findCandidateComponents方法继承自ClassPathScanningCandidateComponentProvider类,是用于查找指定包及其子包下所有匹配的类,并返回这些类对应的BeanDefinition对象。它的源码如下。

    public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
        try {
            // 声明有CLASSPATH_ALL_URL_PREFIX="classpath*:"
            // resourcePattern默认为"**/*.class"
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    resolveBasePackage(basePackage) + "/" + this.resourcePattern;
            // 根据模式匹配来搜索包下面匹配的所有类
            // 默认的ResourcePatternResolver实现类为PathMatchingResourcePatternResolver类
            Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
            boolean traceEnabled = logger.isTraceEnabled();
            boolean debugEnabled = logger.isDebugEnabled();
            // 遍历所有匹配的类
            for (Resource resource : resources) {
                if (traceEnabled) {
                    logger.trace("Scanning " + resource);
                }
                if (resource.isReadable()) {
                    try {
                        // 默认的MetadataReaderFactory实现类为CachingMetadataReaderFactory
                        // 默认返回的是SimpleMetadataReader对象
                        MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
                        // 通过过滤器来判断类对象是否为候选类
                        if (isCandidateComponent(metadataReader)) {
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            sbd.setResource(resource);
                            sbd.setSource(resource);
                            // 候选类必须是一个具体的实现类,并且它的实例化必须是独立的
                            if (isCandidateComponent(sbd)) {
                                if (debugEnabled) {
                                    logger.debug("Identified candidate component class: " + resource);
                                }
                                candidates.add(sbd);
                            } else {
                                if (debugEnabled) {
                                    logger.debug("Ignored because not a concrete top-level class: " + resource);
                                }
                            }
                        } else {
                            if (traceEnabled) {
                                logger.trace("Ignored because not matching any filter: " + resource);
                            }
                        }
                    } catch (Throwable ex) {
                        throw new BeanDefinitionStoreException(
                                "Failed to read candidate component class: " + resource, ex);
                    }
                } else {
                    if (traceEnabled) {
                        logger.trace("Ignored because not readable: " + resource);
                    }
                }
            }
        } catch (IOException ex) {
            throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
        }
        return candidates;
    }

findCandidateComponents方法首先获取指定包及其子包下所有类的资源对象,然后使用CachingMetadataReaderFactory对象获取一个SimpleMetadataReader的MetadataReader对象,SimpleMetadataReader使用ClassReader对象从Resource对象持有的类文件输入流中读取类信息,ClassReader允许通过ClassVisitor对象来访问它持有的类信息。而SimpleMetadataReader使用AnnotationMetadataReadingVisitor访问器把ClassReader存有的类信息分解成类元数据ClassMetadata对象和注解元数据AnnotationMetadata对象。
因此findCandidateComponents方法才可以调用isCandidateComponent(MetadataReader metadataReader)方法来通过过滤器判断当前类是否会被排除在候选类之外,下面是isCandidateComponent方法的源码。

    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        // 首先使用excludeFilters中的过滤器检查当前类是否应该排除
        // 通过exclude-filter标签配置
        for (TypeFilter tf : this.excludeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                return false;
            }
        }
        // 最后使用includeFilters来查看当前类是否候选类
        // 通过include-filter标签配置。
        // 默认为注解类型的过滤器,注解类为spring定义的@Component
        for (TypeFilter tf : this.includeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                return isConditionMatch(metadataReader);
            }
        }
        return false;
    }

如果当前类是候选类,那么为当前类生成一个ScannedGenericBeanDefinition对象,ScannedGenericBeanDefinition继承自GenericBeanDefinition并实现了AnnotatedBeanDefinition接口。
如果类不是一个具体且独立的类,比如抽象类、接口或者非静态内部类,通过反射实例化一个对象的时候是会抛出异常的。因此spring还会判断一次,在findCandidateComponents方法中调用isCandidateComponent(AnnotatedBeanDefinition beanDefinition)方法,它的源码如下。

    /**
    * 判断类是否是一个具体类,并且是一个可以独立实例化的类。
    **/
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return (beanDefinition.getMetadata().isConcrete() && beanDefinition.getMetadata().isIndependent());
    }

通过以上判断排除,最终获得一个ScannedGenericBeanDefinition对象。现在我们第2点ClassPathBeanDefinitionScanner类的 doScan(String… basePackages)方法拿到这个对象后通过调用AnnotationConfigUtils工具类processCommonDefinitionAnnotations静态方法还做了些什么。

2) AnnotationConfigUtils的processCommonDefinitionAnnotations静态方法的源码如下。

    public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
        processCommonDefinitionAnnotations(abd, abd.getMetadata());
    }

processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd)方法把解析类上的注解任务转交给它的另一个重载方法processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata),这是一个只有包访问权限的静态方法,源码如下。

    static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
        // 解析@Lazy注解,设置是否延迟加载
        if (metadata.isAnnotated(Lazy.class.getName())) {
            abd.setLazyInit(attributesFor(metadata, Lazy.class).getBoolean("value"));
        } else if (abd.getMetadata() != metadata && abd.getMetadata().isAnnotated(Lazy.class.getName())) {
            abd.setLazyInit(attributesFor(abd.getMetadata(), Lazy.class).getBoolean("value"));
        }

        // 解析@Primary注解
        if (metadata.isAnnotated(Primary.class.getName())) {
            abd.setPrimary(true);
        }
        // 解析@DependOn注解
        if (metadata.isAnnotated(DependsOn.class.getName())) {
            abd.setDependsOn(attributesFor(metadata, DependsOn.class).getStringArray("value"));
        }

        if (abd instanceof AbstractBeanDefinition) {
            AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
            // 解析@Role注解
            if (metadata.isAnnotated(Role.class.getName())) {
                absBd.setRole(attributesFor(metadata, Role.class).getNumber("value").intValue());
            }
            // 解析@Description注解
            if (metadata.isAnnotated(Description.class.getName())) {
                absBd.setDescription(attributesFor(metadata, Description.class).getString("value"));
            }
        }
    }

3) doScan(String… basePackages)方法还调用AnnotationConfigUtils工具类的applyScopedProxyMode静态方法,这也是一个只有包访问权限的方法,它主要是处理标注在类上的@Scope注解,源码如下。

    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);
        // 创建一个scope代理
        return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
    }

ScopedProxyCreator类的createScopedProxy静态方法源码如下

    public static BeanDefinitionHolder createScopedProxy(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {

        // 调用ScopedProxyUtils工具类的createScopedProxy方法
        return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
    }

工具类ScopedProxyUtils的createScopedProxy静态方法源码如下。

    public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
            BeanDefinitionRegistry registry, boolean proxyTargetClass) {

        String originalBeanName = definition.getBeanName();
        BeanDefinition targetDefinition = definition.getBeanDefinition();
        // targetBeanName格式为scopedTarget. + originalBeanName
        String targetBeanName = getTargetBeanName(originalBeanName);

        // Create a scoped proxy definition for the original bean name,
        // "hiding" the target bean in an internal target definition.
        // 创建一个ScopedProxyFactoryBean类对应BeanDefinition对象
        RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
        proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
        proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
        proxyDefinition.setSource(definition.getSource());
        proxyDefinition.setRole(targetDefinition.getRole());

        proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
        if (proxyTargetClass) {
            targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
        } else {
            // 设置为根据接口做做代理
            proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
        }

        // 根据代理目标BeanDefinition设置是否可以为自动注入的候选bean
        proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
        proxyDefinition.setPrimary(targetDefinition.isPrimary());
        if (targetDefinition instanceof AbstractBeanDefinition) {
            proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
        }

        // 隐藏被代理的bean
        targetDefinition.setAutowireCandidate(false);
        targetDefinition.setPrimary(false);

        // 注册被代理的bean的BeanDefinition对象
        registry.registerBeanDefinition(targetBeanName, targetDefinition);

        // 返回代理bean的BeanDefinitionHolder对象
        return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
    }

总结


(1)component-scan不只是拥有annotation-config的作用,它还用于扫描注册指定包下特定的bean。因此,在xml配置文件中定义了component-scan就不需要再定义annotation-config。

(2)component-scan大大简化了我们的xml配置。如果我们需要把一个对象托管给Spring容器,只需要在类上添加@Component注解或者被@Component标注的注解(比如,@Controller、@Service、@Repository)

(3)component-scan的两个子标签include-filter和exclude-filter不能共存。这个并不是从spring的java源码中体现的,而是在schema文件中体现的。(spring为什么这样设计,我实在是不懂的了)

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值