spring bean自动扫描分析

来源:互联网 发布:二级备案域名购买 编辑:程序博客网 时间:2024/05/16 19:04
Spring为企业级开发提供了轻量而又强大的支持。但是为了使用spring还是需要大量的配置文件对系统中的bean进行配置。虽然提供了基于注解的配置,但其也只能省去依赖部分的配置,而对每个Bean本身的配置仍然需要。为了进一步减少配置,Spring进一步提供了从classpath自动扫描Bean组建并将其对应的BeanDefinination加入到容器中的功能。本文就对spring自动扫描组建的功能进行学习和分析。 

   提供自动扫描功能的核心类是:ClassPathBeanDefinitionScanner,该类根据提供个基础包名,扫描classpath下与该包名的路径下,找到复合条件的类并注册为Spring的一个Bean。 默认情况下,ClassPathBeanDefinitionScanner将会扫面所有用Spring指定了的注解标识了的类,包括:@Component、@Service、@Repository、@Controller(Spring注解配置的详细内容可以参见http://www.ibm.com/developerworks/cn/opensource/os-cn-spring-iocannt/)。也可以对扫描的机制进行配置,设置一些Filter,只有满足Filter的类才能被注册为Bean。 

     有两种方式使用Classpath扫描机制:第一种是直接使用AnnotationConfigApplicationContext,该类有一个scan(String basePackages)方法,可以对指定的包进行扫描;第二种是在Bean配置文件中使用如下配置开启classpath扫描功能: 



Xml代码 
<context:component-scan base-package="com.ronry.springtest.simple" />  

<context:component-scan base-package="com.ronry.springtest.simple" /> 

(注意需要配置context命名空间)。开启扫描功能之后即可按普通的方式从配置文件创建一个ApplicationContext。在ApplicationContext的loadBeanDefinition时遇到component-scan元素时会以ComponentScanBeanDefinitionParser进行解析。 

    但AnnotationConfigApplicationContext和ComponentScanBeanDefinitionParser,内部依赖的都是ClassPathBeanDefinitionScanner。与其相关的主要类如下: 

 


    ResourcePatternResolver用来从classpath中加载Resource;MetadataReaderFactory用来根据Resource生成MetadataReader;BeanNameGenerator用来生成扫描到的Bean在容器中的名字;ScopeMetadataResolver则用来处理扫描到的Bean的Scope。其中需要特别注意的是BeanNameGenerator和ScopeMetadataResolver是可配置的,在ComponentScanBeanDefinitionParser中有两个方法:parseBeanNameGenerator(element, scanner)和parseScope(element, scanner)就是用来处理这两个组件的配置的。如果没有配置,则BeanNameGenerator默认是用AnnotationBeanNameGenerator而ScopeMetadataResolver用的是AnnotationScopeMetadataResolver。 

         而扫描的过程大概为: 


用ResourcePatternResolver从配置的classpath中加载Resource; 
分别处理扫描到的每个Resource,用MetadataReaderFactory生成对应的MetadataReader; 
根据MetadataReader判断Resource是否是符合条件的Component; 
如果是,则生成对应的ScannedGenericBeanDefinition;不是则跳过; 
对于经过上面4步生成的符合条件的ScannedGenericBeanDefinition,先用ScopeMetadataResolver生成ScopeMetadata,将得到的Scope设置到对应的ScannedGenericBeanDefinition中; 
再用BeanNameGenerator生成Bean的名称; 
最后,设置ScannedGenericBeanDefinition的其他属性,例如:dependsOn、lazy、autowired等;根据ScannedGenericBeanDefinition是AbstractBeanDefinition还是AnnotatedBeanDefinition,设置的方法稍有不同。