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示例进入源码可直观感受运行期间的值,源码分析不易,搞清楚主流程与思想比源码本身更重要。