赞
踩
BeanDefinition有三个实现类,ChildBeanDefinition、GenericBeanDefinition、RootBeanDefinition,三者都继承 AbstractBeanDefinition,对三个子类共同的类信息进行抽象。如果配置文件中定义了父 和 子 ,则父 用 RootBeanDefinition表示,子 用 ChildBeanDefinition 表示,而没有父 的就使用RootBeanDefinition 表示。GenericBeanDefinition 为一站式服务类。
之前没有对BeanDefinition属性作详细分析,本文直接开始讲BeanDefintionParserDelegate的方法parseBeanDefinitionAttributes方法。
由于BeanDefinition的实现类都继承自父类AbstractBeanDefinition,父类中有三个引用的属性ConstructorArgumentValues、MutablePropertyValues、MethodOverrides,所以GenericBeanDefinition最终包含的属性如下图:
3.1 流程概览
3.2 详细过程
前面一文提到,自定义标签解析BeanDefinitionParserDelegate类,执行parseCustomElement方法;
上述过程主要完成以下步骤:
step1与step2前文已分析,以component-scan为例,分析step3,代码进入ComponentScanBeanDefinitionParser的parse方法
上述过程总共分为三步:
进入上述step2,进入ClassPathBeanDefinitionScanner的doScan方法,
上述doScan方法主要做了以下三步:
继续进入上述step1中的findCandidateComponents方法,来到ClassPathScanningCandidateComponentProvider类的scanCandidateComponents方法,完成以下步骤:
前面还有一个步骤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的解析,如下图:
- public AutowiredAnnotationBeanPostProcessor() {
- this.autowiredAnnotationTypes.add(Autowired.class);
- this.autowiredAnnotationTypes.add(Value.class);
- try {
- this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
- ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
- logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
- }
- catch (ClassNotFoundException ex) {
- // JSR-330 API not available - simply skip.
- }
- }
类似跟踪CommonAnnotationBeanPostProcessor类,可以看到该类完成@Resource @PostConstruct @PreDestroy的解析,如下图:
- static {
- webServiceRefClass = loadAnnotationType("javax.xml.ws.WebServiceRef");
- ejbClass = loadAnnotationType("javax.ejb.EJB");
-
- resourceAnnotationTypes.add(Resource.class);
- if (webServiceRefClass != null) {
- resourceAnnotationTypes.add(webServiceRefClass);
- }
- if (ejbClass != null) {
- resourceAnnotationTypes.add(ejbClass);
- }
- }
- ......
-
- public CommonAnnotationBeanPostProcessor() {
- setOrder(Ordered.LOWEST_PRECEDENCE - 3);
- setInitAnnotationType(PostConstruct.class);
- setDestroyAnnotationType(PreDestroy.class);
- ignoreResourceType("javax.xml.ws.WebServiceContext");
- }
创建一个BeanDefinitionTest类,实现BeanDefinitionRegistryPostProcessor接口,并在方法中完成设置Bean的类型为BeanClass,然后设置BeanClass对象的username属性与值,最后注册到容器中,代码如下
- @Component
- public class BeanDefinitionTest implements BeanDefinitionRegistryPostProcessor {
-
- @Override
- public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
- GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
- genericBeanDefinition.setBeanClass(BeanClass.class);
-
- MutablePropertyValues propertyValues = genericBeanDefinition.getPropertyValues();
- propertyValues.addPropertyValue("username","wzj");
-
- registry.registerBeanDefinition("beanClass",genericBeanDefinition);
- }
BeanClass类如下:
- @Data
- public class BeanClass {
-
- private String username;
- }
测试类如下:
- public class TestSpring {
-
- @Autowired
- private ApplicationContext applicationContext;
-
- @Test
- public void testComponentScan() {
- applicationContext = new AnnotationConfigApplicationContext("com.wzj");
- BeanClass beanClass = (BeanClass)applicationContext.getBean("beanClass");
- BeanDefinitionTest beanDefinitionTest = (BeanDefinitionTest)applicationContext.getBean("beanDefinitionTest");
- System.out.println("BeanClass-->" + beanClass.getUsername());
- System.out.println("BeanDefinitionTest-->" + beanDefinitionTest.getClass());
- }
代码目录结构如下与运行结果如下
本文以conmponent-scan标签为例,分析了主要流程,并结合源码讲述了BeanDefinition属性的解析、封装、以及最后注册到容器中,最后以一个思维导图总结每个流程中的大致步骤
另外,静态看源码可关注主流程,并做注释,动态debug示例进入源码可直观感受运行期间的值,源码分析不易,搞清楚主流程与思想比源码本身更重要。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。