Spring 的beanDefinition
对于学习Spring而言,BeanDefinition是非常重要的,而且在Spring内部提供多种类型BeanDefinition,下边是Spring官网对BeanDefinition的描述
Within the container itself, these bean definitions are represented as
BeanDefinition
objects, which contain (among other information) the following metadata:
- A package-qualified class name: typically, the actual implementation class of the bean being defined.
- Bean behavioral configuration elements, which state how the bean should behave in the container (scope, lifecycle callbacks, and so forth).
- References to other beans that are needed for the bean to do its work. These references are also called collaborators or dependencies.
- Other configuration settings to set in the newly created object — for example, the size limit of the pool or the number of connections to use in a bean that manages a connection pool.
这里说明一下几个重要的类/接口:
-
BeanDefnition:定义了一些基本常量和对BeanDefinition的基本操作方法
-
-AttributeAccessor:提供属性方法-
-
AttributeAccessorSupport:实现AttributeAccessor
-
GenericBeanDefinition:我们通过xml配置的bean class
最终都会转换为这种类型的BeanDefninition,对于这种类型的BeanDefinition,它既可以作为Parent,
也可以作为Child,在BeanDefinitoin中存在父子的说法,这个类好像是在Spring2.5以后提供的 -
ScannedGenericBeanDefintion:继承GenericBeanDefinition,
我们通过@Component注解的类,最后都会转换为这种类型的BeanDefinition -
AnnotatedGenericBeanDefinition:@Configuration标注的配置类将会被转换为这种类型的BeanDefintion
-
RootBeanDefinition:
这种类型的BeanDefinition只能作为Parent出现,Spring自定义类最后都转换为这种类型的BeanDefinition,在最后实例化bean的时候,所有其他类型都会被转换为RootBeanDefinition -
ChildBeanDefintion:这种类型的BeanDefinition只能作为Child出现
问题:如果同时提供@Component和xml配置, 这时候是什么类型BeanDefinition
根据源码提供,Spring会先解析@CompontScan, 然后将对应包下的所有满足条件的类转换为ScannedGenericBeanDefintion,然后Spring会检查@ImportResource,这个时候会把xml配置文件中的class转换为GenericBeanDefinition, 如果在xml和注解中同时包含相同的类,最后会转换为ScannedGenericBeanDefintion
1.org.spring…由Spring提供
2.config为@Configuration标注的配置类
3.beanTest为@Component和xml同时配置的类
4.entity 为只有@Component标注的类
5.xmlBean为xml配置类
问题:为什么要定义这么多的BeanDefinition,只使用一种不好么?
个人认为,spring该开始也没有考虑这么多,最开始xml和注解类型没有留下的时候,可以通过一些简单的类就可以实现,但是随着这下新型技术出现,Spring也不得不跟上发展的步伐,但是原有的也不能彻底抛弃,所以就创建除了这么多不同的BeanDefinition,针对不同类型的BeanDefinition做不同类型的特殊处理,而且最后在实例化Bean的时候都还要合并成RootBeanDefinition
问题:怎么证明?
1.Spring内部提供的为RootBeanDefinition
这是一段实例化BeanFactory的代码,可以看到内部使用spring自己提供的类被封装成了RootBeanDefinition
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
/**从传入的registry[也就是最开始创建的ApplicationContext, 这里是AnnotationConfigApplicationContext]
* 中获取到 beanFactory;
*
* 如果registry是DefaultListableBeanFactory的继承类, 则直接返回registry
* 如果是GenericApplicationContext,则将其强转为DefaultListableBeanFactory 返回
* 否则返回false
*/
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
//设置依赖比较器,什么时候会用到
//处理时候过程的先后顺序, 主要处理@Order, 需要验证
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
//设置自动装配候选分解器,主要处理@Lazy和做@qualifier支持
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
//BeanDefinitionHolder 是BeanDefinition的持有类,
/**
* BeanDefinitionHolder 提供用了如下属性
* private final BeanDefinition beanDefinition;
* private final String beanName;
* private final String[] aliases;
*/
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
/**
* org.springframework.context.annotation.internalConfigurationAnnotationProcessor
* RootBeanDefinition spring内部自定义bean
* spring 拓展点之一
*/
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
/**
* org.springframework.context.annotation.internalAutowiredAnnotationProcessor
*/
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));
}
2.@Configuration标注类被转换AnnotatedGenericBeanDefinition
我们可以看到在源码中有这样一段,他在register(annotatedClasses);内部,所以源码证明了@Configuration被转换类AnnotatedGenericBeanDefinition
private <T> void doRegisterBean(Class<T> annotatedClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
//实例化一个BeanDefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
....
3.entity 为只有@Component标注的类
查看Spring内部关于basePackage的扫描实现方法,可以知道ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); 所以标注注解被扫描处理的类最终会被转换为ScannedGenericBeanDefinition
//扫描包, 获取到beanDefinition的class
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
//凭借查询路径:classpath*:com/mjlf/spring/addBeantoContext/**/*.class
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//找到当前包下的所有类
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
//拿到metaDeata读取器
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//比对排除过滤器和包含过滤器,判断该类是不是符合BeanDefinition候选条件
if (isCandidateComponent(metadataReader)) {
//将扫描出来, 当前的class生成为ScannedGenericBeanDefinition
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
//判断是否为候选组件,主要依据为是能实例化的类或者内部类,不能是抽象类或者接口, 如果是抽象类就必须标注@Lookup
if (isCandidateComponent(sbd)) {//正常识别, 需要添加到beanDefinitionHolder中
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
} else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
} else {//不包含处理
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
} catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
} else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
5.xmlBean为xml配置类最后会被转换为GenericBeanDefinition
跟着源码可以发现,最终找到xml配置类型的最终会调用这个方法,方法内部使用:
GenericBeanDefinition bd = new GenericBeanDefinition();
/**
* Create a new GenericBeanDefinition for the given parent name and class name,
* eagerly loading the bean class if a ClassLoader has been specified.
*
* xml解析最后会调用这个方法创建BeanDefinition, 所以默认xml配置的bean最后创建出来的BeanDefinition为GenericBeanDefinition
*
* @param parentName the name of the parent bean, if any
* @param className the name of the bean class, if any
* @param classLoader the ClassLoader to use for loading bean classes
* (can be {@code null} to just register bean classes by name)
* @return the bean definition
* @throws ClassNotFoundException if the bean class could not be loaded
*/
public static AbstractBeanDefinition createBeanDefinition(
@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
bd.setBeanClassName(className);
}
}
return bd;
}
3.beanTest为@Component和xml同时配置的类
根据上边的描述,标注注解的会被转换为ScannedGenericBeanDefinition,而xml的会被转换为GenericBeanDefinition,那同时使用两种方法在同一个类上,spring是怎么处理的,我们知道parser.parse(candidates);方法调用用于扫描包,将符合条件的类转换为BeanDefinition,但是@ImportResource对应的xml配置文件是在this.reader.loadBeanDefinitions(configClasses);方法调用中处理的
do {
//获取解析器[ConfigurationClassParser],主要负责扫描包, 然后将需要转换的class转换为BeanDefinition
//很关键, 扫描指定包下的所有类,并将那些需要转换为BeanDefinition的类转换为BeanDefinition
parser.parse(candidates);
//验证,验证@Configuration的类???
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
//移除已经处理过的config
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//获取configuration中@Bean这样的BeanDefinition
//同时处理@Import,@ImportResource
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
//清除已经处理过的ConfigClass
candidates.clear();
...
/**
* Read {@code configurationModel}, registering bean definitions
* with the registry based on its contents.
*/
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
/**
* Read a particular {@link ConfigurationClass}, registering bean definitions
* for the class itself and all of its {@link Bean} methods.
*/
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
//加载@Bean 标注的方法生成的BeanDefinition
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//处理ImportResource
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
anMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//处理ImportResource
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}