zoukankan      html  css  js  c++  java
  • Spring IoC component-scan 节点详解

    前言

    本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本。因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析。

    本篇文章主要分析 context:componment-scan 标签 Spring 是如何解析的。

    正文

    其实 context 开头的标签也是 Spring 自定义的标签,前面介绍过自定义标签的解析,没看过的小伙伴可以看下Spring IoC 自定义标签解析;其中比较重要的就是 spring.handlersspring.schemas 文件的定义,前者定义了标签与命名空间处理器的对应关系,后者定义了命名空间与 XML Schema文件的对应关系。我们可以查找 Spring 中 context 模块的源码中查看这2个文件,并查看其命名空间的定义:

    上面2张图分别对应了 spring.handlersspring.schemas 文件的定义,只显示了与 context 命名空间相关的定义。

    下面开始具体的代码分析,直接从 parseCustomElement() 方法开始,不知道前面的流程的可以查看Spring IoC BeanDefinition 的加载和注册

    自定义标签的解析

    BeanDefinitionParseDelegate#parseCustomElement()

    public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
        // 获取自定义标签的命名空间
        String namespaceUri = getNamespaceURI(ele); 
        if (namespaceUri == null) {
            return null;
        } 
        // 获取自定义标签的处理器,这里解析的是context:component-scan,所以获取的是上图中的ContextNamespaceHandler
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        } 
        // 进行标签的解析,见下文详解
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }
    

    上面方法中获取的 NamespaceHandler 就是 ContextNamespaceHandler,我们看下该类中注册的元素及其对应的解析器:

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

    由上面代码可以看出 component-scan 元素由 ComponentScanBeanDefinitionParser 类去解析。

    component-scan 元素解析

    ComponentScanBeanDefinitionParser#parse

    public BeanDefinition parse(Element element, ParserContext parserContext) {
        // 获取属性basePacket的值
        String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
        // 解析占位符,例如${basePackage}
        basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
        // 解析base-package(允许通过 ",; 	
    " 中的任一符号填写多个),例如: com.leisurexi.one;com.leisurexi.two
        String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
    ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
    
        // 构建和配置ClassPathBeanDefinitionScanner,见下文详解
        ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
        // 使用scanner在指定的包路径进行扫描,返回注册后的BeanDefinition,见下文详解
        Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
        // 注册组件(包括一些内部注解的后置处理器),见下文详解
        registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
    
        return null;
    }
    

    配置 BeanDefinition 扫描器

    ComponetScanBeanDefinitionParser#configureScanner

    protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
        // 是否使用默认的过滤器,默认为true
        boolean useDefaultFilters = true;
        // 如果设置了use-default-filters属性,则使用设置的值
        if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
            useDefaultFilters = Boolean.parseBoolean(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
        }
    
        // 构建ClassPathBeanDefinitionScanner,将bean定义注册委托给scanner类,见下文详解
        ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
        scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
        scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
        // 解析resource-pattern属性
        if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
            scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
        }
    
        try { 
            // 解析name-generator属性
            parseBeanNameGenerator(element, scanner);
        }
        catch (Exception ex) {
            parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
        }
    
        try { 
            // 解析scope-resolver、scoped-proxy属性
            parseScope(element, scanner);
        }
        catch (Exception ex) {
            parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
        }
        // 解析类型过滤器
        parseTypeFilters(element, scanner, parserContext);
    
        return scanner;
    }
    

    创建 BeanDefinition 扫描器

    ComponentScanBeanDefinitionParser#createScanner
    protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
        return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters,readerContext.getEnvironment(), readerContext.getResourceLoader());
    }
    
    // ClassPathBeanDefinitionScanner.java
    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, @Nullable ResourceLoader resourceLoader) {
    
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;
        // 如果使用默认的过滤器,注册默认的过滤器,见下文详解
        if (useDefaultFilters) {
            registerDefaultFilters();
        }
        setEnvironment(environment);
        setResourceLoader(resourceLoader);
    }
    

    注册默认的过滤器

    ClassPathScanningCandidateComponentProvider#registerDefaultFilters
    protected void registerDefaultFilters() { 
        // 将注解@Component添加到includeFilters中,这将隐式的注册所有@Component的派生注解,例如@Repository、@Service、@Controller
        this.includeFilters.add(new AnnotationTypeFilter(Component.class));
        ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
        try { 
            // 如果当前环境中有@ManagedBean,添加到includeFilters中,否则会catch未找到类的异常并忽略
            this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
        }
        catch (ClassNotFoundException ex) {
            // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
        }
        try { 
            // 如果当前环境中有@Named,添加到includeFilters中,否则会catch未找到类的异常并忽略
            this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
        }
        catch (ClassNotFoundException ex) {
            // JSR-330 API not available - simply skip.
        }
    }
    

    扫描包路径下的组件

    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) {
            // 寻找包路径下符合要求的bean定义(最常见的就是使用@Component标注的类)
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
                // 解析@Scope注解,没有标注默认为singleton作用域
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                // 生成bean的名称,见下文详解
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                if (candidate instanceof AbstractBeanDefinition) {
                    // beanDefinition的后置处理,就是设置beanDefinition的一些默认属性,如autowireMode、initMethod等,并且设置AutowireCandidate,
                    // 一般为true代表可以自动装配到其他bean中
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                if (candidate instanceof AnnotatedBeanDefinition) {
                    // 处理公共注解,见下文详解
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
                // 如果beanDefinition通过检查(大多时候是检查是不是第一次注册)
                // 则将definitionHolder添加进注册中心中,如果有同名的bean在这里会直接抛出异常
                if (checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder =
                        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        return beanDefinitions;
    }
    

    上面方法中的 registerBeanDefinition() 方法在Spring IoC 默认标签解析一文中介绍过,这里不再赘述。

    找到候选组件

    ClassPathScanningCandidateComponentProvider#findCandidateComponents
    public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
            return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
        }
        else { 
            // 扫描符合条件的组件
            return scanCandidateComponents(basePackage);
        }
    }
    
    private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
        Set<BeanDefinition> candidates = new LinkedHashSet<>();
        try {
            // 将要扫描的包的路径拼成完整的,例如:com.leisurexi.ioc.context 
            // 会被拼成 classpath*:com/leisurexi/ioc/context/**/*.class
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                resolveBasePackage(basePackage) + '/' + this.resourcePattern;
            // 获取路径下的所有类的资源
            Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); 
            for (Resource resource : resources) {
                // 如果资源是可读的
                if (resource.isReadable()) {
                    try {
                        // 使用metadataReader读取资源,MetadataReader是专门用来访问元数据的类
                        // 包括: 类元数据ClassMetadata、注解元数据AnnotationMetadata等
                        MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                        // 判断该类是不是候选的组件
                        if (isCandidateComponent(metadataReader)) {
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            sbd.setResource(resource);
                            sbd.setSource(resource);
                            // 判断是否是候选组件,默认条件是class不是接口并且不依赖于内部类
                            if (isCandidateComponent(sbd)) { 
                                candidates.add(sbd);
                            }	
                        }
                    }
                    // 省略异常处理...
                }
            }
        }
        // 省略异常处理...
        return candidates;
    }
    

    上面代码中判断该类是不是候选的组件的方法 isCandidateComponent(metadataReader) 一般情况下 是判断该类是否标注了上文中 ClassPathScanningCandidateComponentProvider#registerDefaultFilters() 中的注解 @Component@ManagedBean@Named@Component 注解是肯定会存在与当前环境中的,所以标注了 @Component 或者其派生的注解如:@Repository@Service@Controller 都会被当做候选组件。

    生成 bean 名称

    AnnotationBeanNameGenerator#generateBeanName
    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
        // 如果BeanDefinition是AnnotatedBeanDefinition类型
        if (definition instanceof AnnotatedBeanDefinition) { 
            // 获取自定义的beanName,如 @Component注解的value值
            String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
            // 如果不为空,并且不是空字符串
            if (StringUtils.hasText(beanName)) { 
                // 返回明确的beanName
                return beanName; 
            }
        }
        // 没有手动指定beanName,默认生成一个,是当前类名的首字母小写,如User类的beanName是user
        return buildDefaultBeanName(definition, registry);
    }
    

    处理公共注解

    AnnotationConfigUtils#processCommonDefinitionAnnotations
    static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
        // 如果bean标注了@Lazy注解,进行解析
        AnnotationAttributes lazy = attributesFor(metadata, Lazy.class); 
        if (lazy != null) {
            abd.setLazyInit(lazy.getBoolean("value"));
        }
        else if (abd.getMetadata() != metadata) {
            lazy = attributesFor(abd.getMetadata(), Lazy.class);
            if (lazy != null) {
                abd.setLazyInit(lazy.getBoolean("value"));
            }
        }
        // 解析@Primary注解,自动装配时当出现多个Bean都匹配时,标注了@Primary注解的Bean将作为首选者
        if (metadata.isAnnotated(Primary.class.getName())) {
            abd.setPrimary(true);
        } 
        // 解析@DependsOn注解,表明当前bean需要依赖的bean,会保证依赖的bean会在当前bean前实例化
        AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
        if (dependsOn != null) {
            abd.setDependsOn(dependsOn.getStringArray("value"));
        }
        // 解析@Role注解,用于标识bean的分类,实际用的比较少
        AnnotationAttributes role = attributesFor(metadata, Role.class);
        if (role != null) {
            abd.setRole(role.getNumber("value").intValue());
        } 
        // 解析@Description注解,bean的描述,实际用的比较少
        AnnotationAttributes description = attributesFor(metadata, Description.class);
        if (description != null) {
            abd.setDescription(description.getString("value"));
        }
    }
    

    注册组件

    ComponentScanBeanDefinitionParser#registerComponents

    protected void registerComponents(XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {
    
        Object source = readerContext.extractSource(element);
        CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);
        // 将扫描的所有BeanDefinition添加到compositeDef中
        for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
            compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
        }
    
        boolean annotationConfig = true;
        // 获取annotation-config属性,默认为true
        if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
            annotationConfig = Boolean.parseBoolean(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
        }
        if (annotationConfig) {
            // 向注册中心中注册用于注解的后置处理器,如AutowireAnnotationProcessor、CommonAnnotationProcessor
            Set<BeanDefinitionHolder> processorDefinitions =
                AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
            // 将注册的注解后置处理器的BeanDefinition添加到compositeDef的nestedComponents属性中
            for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
                compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
            }
        }
        // 触发注册事件,默认实现为EmptyReaderEventListener(空实现,没有具体操作)
        readerContext.fireComponentRegistered(compositeDef);
    }
    

    注册注解处理器

    AnnotationConfigUtils#registerAnnotationConfigProcessors

    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {
        // 获取beanFactory
        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                // 设置dependencyComparator属性
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }
            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                // 设置autowireCandidateResolver属性(设置自动注入候选对象的解析器
                // 用于判断BeanDefinition是否为候选对象)
                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
            }
        }
    
        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
        // 注册用于处理@Configuration注解的后置处理器
        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            // 创建一个ConfigurationClassPostProcessor的BeanDefinition
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            // 将def添加进注册中心
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        // 注册用于处理@Autowired、@Value、@Inject注解的后置处理器
        if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
    
        // 注册用于处理@Resource、@PostConstructor、@PostDestroy注解的后置处理器
        if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
    
        // 注册用于处理JPA注解的后置处理器,如@PersistenceContext、@PersistenceUnit
        if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition();
            try {
    def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
    						AnnotationConfigUtils.class.getClassLoader()));
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                    "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
            }
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        // 注册用于处理@EventListener注解的后置处理器
        if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
        }
        // 注册内部管理用于生产ApplicationListener对象的EventListenerFactory对象
        if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
        }
    
        return beanDefs;
    }
    

    总结

    本文主要介绍了 Spring 解析 context:component-scan 标签的解析流程,我们可以重新整理一下思路:

    1. 首先添加默认的过滤器,也就是判定哪些类会被作为组件来注册;比如默认过滤器添加后,会将标注了 @Component 注解以及它的派生注解当做组件注册。
    2. 找到指定包路径下所有符合条件的类并封装成 BeanDefinition ;解析 @Scope 注解,没有默认为 singleton;生成 bean 的名称,首先会用 @Componentvalue 属性,如果为空或空字符串则默认使用类名,并把首字母转成小写;然后对一些注解的解析,如 @Lazy@Primary@DependsOn等;最后检查注册中心中是否包含当前 beanName,如果没有直接添加进注册中心,否则如果不是同一个类会抛出异常。比如 com.leisurexi.a.Usercom.leisurexi.b.User 同时添加 @Component 注解并且不手动指定不同的 beanName 在启动时就会抛出异常。
    3. 最后注册中心注册一些注解的后置处理器,如下:
      • 处理 @Configuration 注解的 ConfigurationClassPostProcessor
      • 处理 @Autowired@Value@Inject 注解的 AutowiredAnnotationBeanPostProcessor
      • 处理 @Resource@PostConstructor@PostDestroy 注解的 CommonAnnotationBeanPostProcessor
      • 处理JPA注解的 PersistenceAnnotationBeanPostProcessor
      • 处理 @EventListener 注解的 EventListenerMethodProcessor

    最后,我模仿 Spring 写了一个精简版,代码会持续更新。地址:https://github.com/leisurexi/tiny-spring

  • 相关阅读:
    Linux iptables常用命令
    Docker数据卷
    Ubuntu14.04下安装docker 1.9
    初识微服务
    初识微服务
    无状态服务(stateless service)
    git生成ssh key 避免每次push都要输入账号密码
    fiddler和xampp安装成功后,网站打不开的原因
    ajax设置自定义请求头信息
    ajax跨域之设置Access-Control-Allow-Origin
  • 原文地址:https://www.cnblogs.com/leisurexi/p/13088395.html
Copyright © 2011-2022 走看看