当前位置:   article > 正文

Spring源码解析之BeanDefinition

beandefinition

BeanDefinition简介

BeanDefinition有三个实现类,ChildBeanDefinition、GenericBeanDefinition、RootBeanDefinition,三者都继承 AbstractBeanDefinition,对三个子类共同的类信息进行抽象。如果配置文件中定义了父 和 子 ,则父 用 RootBeanDefinition表示,子 用 ChildBeanDefinition 表示,而没有父 的就使用RootBeanDefinition 表示。GenericBeanDefinition 为一站式服务类。

2. BeanDefinition的属性

之前没有对BeanDefinition属性作详细分析,本文直接开始讲BeanDefintionParserDelegate的方法parseBeanDefinitionAttributes方法。

由于BeanDefinition的实现类都继承自父类AbstractBeanDefinition,父类中有三个引用的属性ConstructorArgumentValues、MutablePropertyValues、MethodOverrides,所以GenericBeanDefinition最终包含的属性如下图:

  • id:Bean 的唯一标识名。它必须是合法的 XMLID,在整个 XML 文档中唯一;
  • name:用来为 id 创建一个或多个别名。它可以是任意的字母符合。多个别名之间用逗号或空格分开;
  • class:用来定义类的全限定名(包名+类名)。只有子类 Bean 不用定义该属性;
  • parent:子类 Bean 定义它所引用它的父类 Bean,这是前面的 class 属性失效,子类 Bean 会继承父类 Bean 的所有属性,子类 Bean 也可以覆盖父类 Bean 的属性,注意:子类 Bean 和父类 Bean 是同一个 Java 类;
  • abstract(默认为"false"):用来定义 Bean 是否为抽象 Bean。它表示这个 Bean 将不会被实例化,一般用于父类 Bean,因为父类 Bean 主要是供子类 Bean 继承使用;
  • lazy-init(默认为"false"):用来定义这个 Bean 是否实现懒初始化。如果为"false",它将在 BeanFactory 启动时初始化所有的 SingletonBean。反之,如果为"true",它只在 Bean 请求时才开始创建 SingletonBean;
  • autowire(自动装配,默认为"default"):它定义了 Bean 的自动装载方式;
    --"no":不使用自动装配功能;--"byName":通过 Bean 的属性名实现自动装配;--"byType":通过 Bean 的类型实现自动装配;--"constructor":类似于 byType,但它是用于构造函数的参数的自动组装;--"autodetect":通过 Bean 类的反省机制(introspection)决定是使用"constructor"还是使用"byType"。
  • depends-on(依赖对象):这个 Bean 在初始化时依赖的对象,这个对象会在这个 Bean 初始化之前创建;
  • init-method:用来定义 Bean 的初始化方法,它会在 Bean 组装之后调用。它必须是一个无参数的方法;
  • destroy-method:用来定义 Bean 的销毁方法,它在 BeanFactory 关闭时调用。同样,它也比
    须是一个无参数的方法。它只能应用于 singletonBean。
  • factory-method:定义创建该 Bean 对象的工厂方法。它用于下面的"factory-bean",表示这个 Bean 是通过工厂方法创建,此时,"class"属性失效。
  • factory-bean:定义创建该 Bean 对象的工厂类。如果使用了"factory-bean"则"class"属性失效。
  • autowire-candidate:采用 xml 格式配置 bean 时,将元素的 autowire-candidate属性设置为 false,这样容器在查找自动装配对象时,将不考虑该 bean,即它不会被考虑作为其它 bean自动装配的候选者,但是该 bean 本身还是可以使用自动装配来注入其它 bean 的;
  • MutablePropertyValues:用于封装标签的信息,其实类里面就是有一个 list,list里面是 PropertyValue 对象,PropertyValue 就是一个 name 和 value 属性,用于封装标签的名称和值信息
  • ConstructorArgumentValues:用于封装标签的信息,其实类里面就是有一个 map,map 中用构造函数的参数顺序作为 key,值作为 value 存储到 map 中;
  • MethodOverrides:用于封装 lookup-method 和 replaced-method 标签的信息,同样的类里面有一个 Set 对象添加 LookupOverride 对象和ReplaceOverride 对象。

3. component-scan标签解析过程

3.1 流程概览

3.2 详细过程

前面一文提到,自定义标签解析BeanDefinitionParserDelegate类,执行parseCustomElement方法;

上述过程主要完成以下步骤:

  • step1: 获取namespaceURI;
  • step2: 解析namespaceURI对应的handler类;
  • step3:执行handler方法解析。

step1与step2前文已分析,以component-scan为例,分析step3,代码进入ComponentScanBeanDefinitionParser的parse方法

上述过程总共分为三步:

  • step1:configureScanner方法创建扫描器;
  • step2:doScan方法扫描器扫描;
  • step3:registerComponents注册bean包含的组件。

进入上述step2,进入ClassPathBeanDefinitionScanner的doScan方法,

上述doScan方法主要做了以下三步:

  • step1: findCandidateComponents扫描有注解的类并封装成beanDefinition对象;
  • step2: processCommonDefinitionAnnotations方法支持@Lazy @Primary @DependOn注解;
  • step3:注册BeanDefinition。

继续进入上述step1中的findCandidateComponents方法,来到ClassPathScanningCandidateComponentProvider类的scanCandidateComponents方法,完成以下步骤:

  • step1: getResources递归获取.class后缀的文件;
  • step2: getMetadataReader方法,获取元数据AnnotationMetadataReadingVisitor对象,该元数据收集了扫描类的任何信息;
  • step3:判断includeFilters是否跟元数据中的注解匹配,如果匹配就实例化该类,创建BeanDefinition对象。

前面还有一个步骤step3:registerComponents注册bean包含的组件还未分析,进入该方法

随后进入AnnotationConfigUtils.registerAnnotationConfigProcessors,

上面提到了三类处理器ConfigurationClassPostProcessor,AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,分别对不同注解作处理,最后封装到BeanDefinition中,注册到容器。

进入ConfigurationClassPostProcessor的processConfigBeanDefinitions方法,如下:

上述方法主要解析加了@Configuration的类,以及@Component @ComponentScan @ComponentScans @Bean @Import @ImportResource注解,后者是通过parse方法完成的,进入parse方法一路走下来回到processConfigurationClass方法,如下图

随后进入doProcessConfigurationClass方法,完成@Component @ComponentScan @ComponentScans @Bean @Import @ImportResource注解解析。

同样跟踪AutowiredAnnotationBeanPostProcessor类,可以看到该类完成@Autowired @Value的解析,如下图:

  1. public AutowiredAnnotationBeanPostProcessor() {
  2. this.autowiredAnnotationTypes.add(Autowired.class);
  3. this.autowiredAnnotationTypes.add(Value.class);
  4. try {
  5. this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
  6. ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
  7. logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
  8. }
  9. catch (ClassNotFoundException ex) {
  10. // JSR-330 API not available - simply skip.
  11. }
  12. }

类似跟踪CommonAnnotationBeanPostProcessor类,可以看到该类完成@Resource @PostConstruct @PreDestroy的解析,如下图:

  1. static {
  2. webServiceRefClass = loadAnnotationType("javax.xml.ws.WebServiceRef");
  3. ejbClass = loadAnnotationType("javax.ejb.EJB");
  4. resourceAnnotationTypes.add(Resource.class);
  5. if (webServiceRefClass != null) {
  6. resourceAnnotationTypes.add(webServiceRefClass);
  7. }
  8. if (ejbClass != null) {
  9. resourceAnnotationTypes.add(ejbClass);
  10. }
  11. }
  12. ......
  13. public CommonAnnotationBeanPostProcessor() {
  14. setOrder(Ordered.LOWEST_PRECEDENCE - 3);
  15. setInitAnnotationType(PostConstruct.class);
  16. setDestroyAnnotationType(PreDestroy.class);
  17. ignoreResourceType("javax.xml.ws.WebServiceContext");
  18. }

4. 示例

创建一个BeanDefinitionTest类,实现BeanDefinitionRegistryPostProcessor接口,并在方法中完成设置Bean的类型为BeanClass,然后设置BeanClass对象的username属性与值,最后注册到容器中,代码如下

  1. @Component
  2. public class BeanDefinitionTest implements BeanDefinitionRegistryPostProcessor {
  3. @Override
  4. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
  5. GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
  6. genericBeanDefinition.setBeanClass(BeanClass.class);
  7. MutablePropertyValues propertyValues = genericBeanDefinition.getPropertyValues();
  8. propertyValues.addPropertyValue("username","wzj");
  9. registry.registerBeanDefinition("beanClass",genericBeanDefinition);
  10. }

BeanClass类如下:

  1. @Data
  2. public class BeanClass {
  3. private String username;
  4. }

测试类如下:

  1. public class TestSpring {
  2. @Autowired
  3. private ApplicationContext applicationContext;
  4. @Test
  5. public void testComponentScan() {
  6. applicationContext = new AnnotationConfigApplicationContext("com.wzj");
  7. BeanClass beanClass = (BeanClass)applicationContext.getBean("beanClass");
  8. BeanDefinitionTest beanDefinitionTest = (BeanDefinitionTest)applicationContext.getBean("beanDefinitionTest");
  9. System.out.println("BeanClass-->" + beanClass.getUsername());
  10. System.out.println("BeanDefinitionTest-->" + beanDefinitionTest.getClass());
  11. }

代码目录结构如下与运行结果如下

5. 总结

本文以conmponent-scan标签为例,分析了主要流程,并结合源码讲述了BeanDefinition属性的解析、封装、以及最后注册到容器中,最后以一个思维导图总结每个流程中的大致步骤

另外,静态看源码可关注主流程,并做注释,动态debug示例进入源码可直观感受运行期间的值,源码分析不易,搞清楚主流程与思想比源码本身更重要。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/609290
推荐阅读
相关标签
  

闽ICP备14008679号