一、什么是BeanDefinition
- BeanDefinition描述了Bean的定义,包括该bean有哪些属性、构造函数参数、作用域、是否是抽象的等.
- 在Spring中是根据BeanDefinition来创建Bean的.
- BeanDefinition是Spring非常核心的概念.
1.1.BeanDefinition源码介绍
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
/***常量定义***/
...
/**父Definition名称设置**/
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
/**当前Bean对应的class名称**/
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
/**当前bean的作用域**/
void setScope(@Nullable String scope);
@Nullable
String getScope();
/**是否懒加载**/
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
/**当前bean的依赖**/
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
/**当bean被按类型注入到其他bean时,是否作为候选Bean**/
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
/**是否为主要bean,当前容器有多个当前类型的bean**/
void setPrimary(boolean primary);
boolean isPrimary();
/**设置工厂Bean的名称**/
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
/**设置工厂bean中工厂方法的名称**/
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
/**获取当前构造器参数**/
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
/**获取当前bean的属性集合**/
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
/**当前bean的作用域**/
boolean isSingleton();
boolean isPrototype();
/**当前Bean是否是抽象Bean**/
boolean isAbstract();
/**当前bean的角色
int ROLE_APPLICATION = 0; //用户自己定义的 Bean
int ROLE_SUPPORT = 1; //来源于配置文件的 Bean
int ROLE_INFRASTRUCTURE = 2;//Spring 内部的 Bean
**/
int getRole();
/**bean的描述**/
@Nullable
String getDescription();
/**bean资源文件的描述**/
@Nullable
String getResourceDescription();
/**如果当前 BeanDefinition 是一个代理对象,那么该方法可以用来返回原始的 BeanDefinitio**/
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
1.2.BeanDefinition体系介绍
1.2.1.BeanDefinition、AbstractBeanDefinition
BeanDefinition
bean定义接口,定义了Bean相关信息的设置、获取接口.
AbstractBeanDefinition
是所有具体的BeanDefinition的基类,定义了BeanDefinition的通用属性.
1.2.3.GenericBeanDefinition、ChildBeanDefinition、RootBeanDefinition
1.2.3.1.ChildBeanDefinition、RootBeanDefinition
ChildBeanDefinition
ChildBeanDefinition一般在Bean存在父子关系时,子类bean的BeanDefinition一般用该类型表示,但是从spring2.5开始,推荐使用GenericBeanDefinition.
RootBeanDefinition
根BeanDefinition,可以理解为Spring 运行时统一的Bean定义视图.如果一个Bean来源于多个多个原始Bean的定义,它在运行时会从这多个Bean定义抽出出来属性,生成一个RootBeanDefinition,该BeanDefintion不能设置parentName,因为它已经将parent相关的信息copy了过来,如果存在parent BeanDefinition的话.从spring 2.5以后,如果注册一个BeanDefinition推荐使用GenericeBeanDefinition
1.2.3.2.GenericBeanDefinition
GenericBeanDefinition is a one-stop shop for standard bean definition purposes.
- GenericBeanDefinition是用于标准bean定义的一站式格式.
- 可以选择性的指定构造函数参数值和类属性值,可以通过parentName设置父bean 的名称.
- 可以通过post-processor来处理该BeanDefinition,甚至可以重新配置父名称.
1.2.4.ScannedGenericBeanDefinition、AnnotatedGenericeBeanDefinition、ConfigurationClassBeanDefinition
1.2.4.1.ScannedGenericBeanDefinition
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
/**
* Create a new ScannedGenericBeanDefinition for the class that the
* given MetadataReader describes.
* @param metadataReader the MetadataReader for the scanned target class
*/
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
Assert.notNull(metadataReader, "MetadataReader must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
setBeanClassName(this.metadata.getClassName());
}
@Override
public final AnnotationMetadata getMetadata() {
return this.metadata;
}
@Override
@Nullable
public MethodMetadata getFactoryMethodMetadata() {
return null;
}
}
通过类名我们也可以看出BeanDefintion和扫描类有关.
我们一般在spring应用中会配置扫描根路径,那么从该根路径下扫描到的@Controller、@Service、@Component等Bean定义的类,就会生成对应的ScannedGenericBeanDefinition.
从.class中获取Bean的配置元信息.
1.2.4.1.AnnotatedGenericeBeanDefinition
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
@Nullable
private MethodMetadata factoryMethodMetadata;
/**
* Create a new AnnotatedGenericBeanDefinition for the given bean class.
* @param beanClass the loaded bean class
*/
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = new StandardAnnotationMetadata(beanClass, true);
}
/**
* Create a new AnnotatedGenericBeanDefinition for the given annotation metadata,
* allowing for ASM-based processing and avoidance of early loading of the bean class.
* Note that this constructor is functionally equivalent to
* {@link org.springframework.context.annotation.ScannedGenericBeanDefinition
* ScannedGenericBeanDefinition}, however the semantics of the latter indicate that a
* bean was discovered specifically via component-scanning as opposed to other means.
* @param metadata the annotation metadata for the bean class in question
* @since 3.1.1
*/
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
Assert.notNull(metadata, "AnnotationMetadata must not be null");
if (metadata instanceof StandardAnnotationMetadata) {
setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
}
else {
setBeanClassName(metadata.getClassName());
}
this.metadata = metadata;
}
/**
* Create a new AnnotatedGenericBeanDefinition for the given annotation metadata,
* based on an annotated class and a factory method on that class.
* @param metadata the annotation metadata for the bean class in question
* @param factoryMethodMetadata metadata for the selected factory method
* @since 4.1.1
*/
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata, MethodMetadata factoryMethodMetadata) {
this(metadata);
Assert.notNull(factoryMethodMetadata, "MethodMetadata must not be null");
setFactoryMethodName(factoryMethodMetadata.getMethodName());
this.factoryMethodMetadata = factoryMethodMetadata;
}
@Override
public final AnnotationMetadata getMetadata() {
return this.metadata;
}
@Override
@Nullable
public final MethodMetadata getFactoryMethodMetadata() {
return this.factoryMethodMetadata;
}
}
该类和ScannedGenericBeanDefinition有点类似,支持通过注解信息来生成BeanDefinition.
从在spring的应用中来看,是作为一个BeanDefintion定义文件的一个入口,类型xml,在SpringBoot中,我们一般会这样使用:
@SpringBootApplication
public class SpringMvcApp {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringMvcApp.class,args);
}
}
那么SpringMvcApp这个类就会生成一个AnnotatedGenericBeanDefinition,然后获取当前spring应用bean扫描的路径等信息.
可以理解为一个入口类.
一般在ApplicationContext.refresh调用之前,注册到当前BeanRegistry中,然后在refresh过程中,会根据当前类的配置信息,初始化对应路径的bean.
1.2.4.1.ConfigurationClassBeanDefinition
private static class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata annotationMetadata;
private final MethodMetadata factoryMethodMetadata;
public ConfigurationClassBeanDefinition(ConfigurationClass configClass, MethodMetadata beanMethodMetadata) {
this.annotationMetadata = configClass.getMetadata();
this.factoryMethodMetadata = beanMethodMetadata;
setLenientConstructorResolution(false);
}
public ConfigurationClassBeanDefinition(
RootBeanDefinition original, ConfigurationClass configClass, MethodMetadata beanMethodMetadata) {
super(original);
this.annotationMetadata = configClass.getMetadata();
this.factoryMethodMetadata = beanMethodMetadata;
}
private ConfigurationClassBeanDefinition(ConfigurationClassBeanDefinition original) {
super(original);
this.annotationMetadata = original.annotationMetadata;
this.factoryMethodMetadata = original.factoryMethodMetadata;
}
@Override
public AnnotationMetadata getMetadata() {
return this.annotationMetadata;
}
@Override
public MethodMetadata getFactoryMethodMetadata() {
return this.factoryMethodMetadata;
}
@Override
public boolean isFactoryMethod(Method candidate) {
return (super.isFactoryMethod(candidate) && BeanAnnotationHelper.isBeanAnnotated(candidate));
}
@Override
public ConfigurationClassBeanDefinition cloneBeanDefinition() {
return new ConfigurationClassBeanDefinition(this);
}
}
该类是@Configuration标记的类对应生成的BeanDefinition,会设置对应的工厂信息/工厂方法信息.
二、如何使用
我们现在已经了解了BeanDefinition的几种实现,那么我们如何动态的添加BeanDefintion到BeanFactory中.
2.1.ImportBeanDefinitionRegistrar+BeanDefinitionRegistryPostProcessor方式
我们从之前介绍@Configuration的文章可以知道,在解析@Configuration类时,会解析@Import 引入的ImportBeanDefinitionRegistrar的子类,并调用registerBeanDefinitions该方法.
在该方法中我们可以手动的注册BeanDefintion,那么我们可以在这里做以下操作.
- 可以注册一组BeanDefintion
- 可以注册一个BeanDefintion,但是该BeanDefinition对应的类实现了BeanDefinitionRegistryPostProcessor接口,这样在调用postProcessBeanDefinitionRegistry做一些根据当前注解元信息扫描类并加载到当前BeanDefinitionRegistry的操作.
mybatis-spring-boot-starter 的原理就是通过第二种方式实现.
我们简单看下:
MapperScan注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan
MapperScannerRegistrar
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
/**
* {@inheritDoc}
*
* @deprecated Since 2.0.2, this method not used never.
*/
@Override
@Deprecated
public void setResourceLoader(ResourceLoader resourceLoader) {
// NOP
}
/**
* {@inheritDoc}
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes mapperScanAttrs = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
if (mapperScanAttrs != null) {
registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
generateBaseBeanName(importingClassMetadata, 0));
}
}
void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
builder.addPropertyValue("processPropertyPlaceHolders", true);
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
builder.addPropertyValue("annotationClass", annotationClass);
}
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
builder.addPropertyValue("markerInterface", markerInterface);
}
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
}
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
}
String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
if (StringUtils.hasText(sqlSessionTemplateRef)) {
builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
}
String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
if (StringUtils.hasText(sqlSessionFactoryRef)) {
builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
}
List<String> basePackages = new ArrayList<>();
basePackages.addAll(
Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText)
.collect(Collectors.toList()));
basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName)
.collect(Collectors.toList()));
if (basePackages.isEmpty()) {
basePackages.add(getDefaultBasePackage(annoMeta));
}
String lazyInitialization = annoAttrs.getString("lazyInitialization");
if (StringUtils.hasText(lazyInitialization)) {
builder.addPropertyValue("lazyInitialization", lazyInitialization);
}
String defaultScope = annoAttrs.getString("defaultScope");
if (!AbstractBeanDefinition.SCOPE_DEFAULT.equals(defaultScope)) {
builder.addPropertyValue("defaultScope", defaultScope);
}
builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
// for spring-native
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
private static String generateBaseBeanName(AnnotationMetadata importingClassMetadata, int index) {
return importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index;
}
private static String getDefaultBasePackage(AnnotationMetadata importingClassMetadata) {
return ClassUtils.getPackageName(importingClassMetadata.getClassName());
}
/**
* A {@link MapperScannerRegistrar} for {@link MapperScans}.
*
* @since 2.0.0
*/
static class RepeatingRegistrar extends MapperScannerRegistrar {
/**
* {@inheritDoc}
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes mapperScansAttrs = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScans.class.getName()));
if (mapperScansAttrs != null) {
AnnotationAttributes[] annotations = mapperScansAttrs.getAnnotationArray("value");
for (int i = 0; i < annotations.length; i++) {
registerBeanDefinitions(importingClassMetadata, annotations[i], registry,
generateBaseBeanName(importingClassMetadata, i));
}
}
}
}
}
注册一个MapperScannerConfigurer类对应的BeanDefintion
MapperScannerConfigurer
public class MapperScannerConfigurer
implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
...
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
if (StringUtils.hasText(lazyInitialization)) {
scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
}
if (StringUtils.hasText(defaultScope)) {
scanner.setDefaultScope(defaultScope);
}
scanner.registerFilters();
scanner.scan(
StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
...
}
在AbstractApplicationContext.refresh的
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
阶段调用,扫描相关路径的class注册到BeanDefinitionRegistry.