BeanDefinition
在 Spring 容器中,我们广泛使用的是一个一个的 Bean,那在Spring 中,我们可以如何去定义一个Bean?
还有就是可以通过BeanDefinition 这个类。
比如,我们可以通过定义一个BeanDefinition 对象来表示定义了一个Bean:
首先项目中添加 spring-context 依赖,如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
然后在创建User 类
public class User {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void init(){
System.out.println("初始化");
}
}
public static void main(String[] args) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("user", beanDefinition);
System.out.println(beanFactory.getBean("user"));
}
结果:com.gongj.entity.User@70177ecd
我们还可以通过BeanDefinition 设置一个Bean 的其他属性
beanDefinition.setScope("prototype");
beanDefinition.setInitMethodName("init");
beanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE);
结果:
初始化
com.gongj.entity.User@1e88b3c
注:User类中需要添加初始化方法 init()
总之,我们通过,@Bean ,@Component 等方式所定义的Bean,最终都会被解析为BeanDefinition 对象。要理解 BeanDefinition ,我们从 BeanDefinition 的继承关系开始看起:
可以看到 BeanDefinition 是一个接口,继承自 BeanMetadataElement 和 AttributeAccessor 接口。
- AttributeAccessor:定义用于附加和访问元数据的通用协定的接口,可以是任意对象。具体的实现则是
AttributeAccessorSupport ,采用 LinkedHashMap 进行存储。
public interface AttributeAccessor {
void setAttribute(String name, Object value);
Object getAttribute(String name);
Object removeAttribute(String name);
boolean hasAttribute(String name);
String[] attributeNames();
}
- BeanMetadataElement:该接口只有一个方法 getSource,该方法返回 Bean 的来源。
这是 BeanDefinition 所继承的两个接口。接下来我们来看下 BeanDefinition 本身:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
void setScope(@Nullable String scope);
@Nullable
String getScope();
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
void setPrimary(boolean primary);
boolean isPrimary();
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();
void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();
void setRole(int role);
int getRole();
void setDescription(@Nullable String description);
@Nullable
String getDescription();
ResolvableType getResolvableType();
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
@Nullable
String getResourceDescription();
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
BeanDefinition 实现类
BeanDefinition 是一个接口,它有多个实现类,这些实现类分别描述不同类型的 Bean。大致分为两种:
- 抽象实现:
AbstractBeanDefinition - 子接口:
AnnotatedBeanDefinition
再来看一张继承关系图: 删除了一些无关的继承关系,最终形成了上面那副图。
抽象实现:AbstractBeanDefinition
AbstractBeanDefinition 是一个抽象类,BeanDefinition 中只是定义了一系列的 get/set 方法,并没有提供对应的属性,在 AbstractBeanDefinition 中将所有的属性定义出来了。该抽象类下有个三个子类:GenericBeanDefinition 、RootBeanDefinition 、ChildBeanDefinition 。我们先来看 AbstractBeanDefinition 本身的一些方法与属性。
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
public static final String SCOPE_DEFAULT = "";
public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
@Deprecated
public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
public static final int DEPENDENCY_CHECK_NONE = 0;
public static final int DEPENDENCY_CHECK_OBJECTS = 1;
public static final int DEPENDENCY_CHECK_SIMPLE = 2;
public static final int DEPENDENCY_CHECK_ALL = 3;
public static final String INFER_METHOD = "(inferred)";
@Nullable
private volatile Object beanClass;
@Nullable
private String scope = SCOPE_DEFAULT;
private boolean abstractFlag = false;
@Nullable
private Boolean lazyInit;
private int autowireMode = AUTOWIRE_NO;
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
@Nullable
private String[] dependsOn;
private boolean autowireCandidate = true;
private boolean primary = false;
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();
@Nullable
private Supplier<?> instanceSupplier;
private boolean nonPublicAccessAllowed = true;
private boolean lenientConstructorResolution = true;
@Nullable
private String factoryBeanName;
@Nullable
private String factoryMethodName;
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
@Nullable
private MutablePropertyValues propertyValues;
private MethodOverrides methodOverrides = new MethodOverrides();
@Nullable
private String initMethodName;
@Nullable
private String destroyMethodName;
private boolean enforceInitMethod = true;
private boolean enforceDestroyMethod = true;
private boolean synthetic = false;
private int role = BeanDefinition.ROLE_APPLICATION;
@Nullable
private String description;
@Nullable
private Resource resource;
}
RootBeanDefinition
这是一个最常用的实现类,Spirng 去创建 Bean 时是基于RootBeanDefinition 去创建的!RootBeanDefinition 继承了AbstractBeanDefinition ,在AbstractBeanDefinition 的基础上扩展了一些之外的功能,并且RootBeanDefinition 是没有父BeanDefinition 的。
public class RootBeanDefinition extends AbstractBeanDefinition {
@Nullable
private BeanDefinitionHolder decoratedDefinition;
@Nullable
private AnnotatedElement qualifiedElement;
volatile boolean stale;
boolean allowCaching = true;
boolean isFactoryMethodUnique = false;
@Nullable
volatile ResolvableType targetType;
@Nullable
volatile Class<?> resolvedTargetType;
@Nullable
volatile Boolean isFactoryBean;
@Nullable
volatile ResolvableType factoryMethodReturnType;
@Nullable
volatile Method factoryMethodToIntrospect;
final Object constructorArgumentLock = new Object();
@Nullable
Executable resolvedConstructorOrFactoryMethod;
boolean constructorArgumentsResolved = false;
@Nullable
Object[] resolvedConstructorArguments;
@Nullable
Object[] preparedConstructorArguments;
final Object postProcessingLock = new Object();
boolean postProcessed = false;
@Nullable
volatile Boolean beforeInstantiationResolved;
@Nullable
private Set<Member> externallyManagedConfigMembers;
@Nullable
private Set<String> externallyManagedInitMethods;
@Nullable
private Set<String> externallyManagedDestroyMethods;
@Override
public String getParentName() {
return null;
}
@Override
public void setParentName(@Nullable String parentName) {
if (parentName != null) {
throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
}
}
}
实践
复用开篇就用到的 User 类,不过在其中添加toString 方法。
public static void main(String[] args) {
DefaultListableBeanFactory context = new DefaultListableBeanFactory();
MutablePropertyValues mpvs = new MutablePropertyValues();
mpvs.add("id",4L);
mpvs.add("name","gongj");
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class,null,mpvs);
context.registerBeanDefinition("user",rootBeanDefinition);
User user = (User)context.getBean("user");
System.out.println(user);
}
结果:User{id=4, name='gongj'}
ChildBeanDefinition
该类继承自 AbstractBeanDefinition 。其相当于一个子类,不可以单独存在,必须依赖一个父 BeanDetintion ,构造 ChildBeanDefinition 时,通过构造方法传入父 BeanDetintion 的名称或通过 setParentName 设置父名称。它可以从父类继承方法参数、属性值,并可以重写父类的方法,同时也可以增加新的属性或者方法。
从 Spring 2.5 开始,以编程方式注册 Bean 定义的首选方法是 GenericBeanDefinition,GenericBeanDefinition 可以有效替代 ChildBeanDefinition 的绝大分部使用场合。
实践
新建一个 Person 类,Person 类在 User 类的基础上增加一个 address 属性。
public class Person {
private Long id;
private String name;
private String address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
启动
public static void main(String[] args) {
DefaultListableBeanFactory context = new DefaultListableBeanFactory();
MutablePropertyValues mpvs = new MutablePropertyValues();
mpvs.add("id",4L);
mpvs.add("name","gongj");
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class,null,mpvs);
context.registerBeanDefinition("user",rootBeanDefinition);
MutablePropertyValues childValues = new MutablePropertyValues();
childValues.add("address","上海市");
ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition("user", Person.class,null,childValues);
context.registerBeanDefinition("person", childBeanDefinition);
User user = context.getBean(User.class);
Person person = context.getBean(Person.class);
System.out.println("user = " + user);
System.out.println("person = " + person);
}
结果:
user = User{id=4, name='gongj'}
person = Person{id=4, name='gongj', address='上海市'}
GenericBeanDefinition
GenericBeanDefinition 是从 Spring2.5 以后新加入的 bean 文件配置属性定义类,是一站式服务类。GenericBeanDefinition 可以动态设置父 Bean,同时兼具 RootBeanDefinition 和 ChildBeanDefinition 的功能。
GenericBeanDefinition 的实现比较简单,在 AbstractBeanDefinition 的基础上只增加了parentName 的功能,其余的实现都在父类 AbstractBeanDefinition 里。 注:若你是xml配置,会解析所有属性并统一封装至 GenericBeanDefinition 类型的实例中,之后再逐渐解析的。
实践
public static void main(String[] args) {
DefaultListableBeanFactory ctx = new DefaultListableBeanFactory();
MutablePropertyValues mpvs = new MutablePropertyValues();
mpvs.add("id",4L);
mpvs.add("name","gongj");
GenericBeanDefinition parentGenericBeanDefinition = new GenericBeanDefinition();
parentGenericBeanDefinition.setBeanClass(User.class);
parentGenericBeanDefinition.setPropertyValues(mpvs);
ctx.registerBeanDefinition("user",parentGenericBeanDefinition);
GenericBeanDefinition childGenericBeanDefinition = new GenericBeanDefinition();
childGenericBeanDefinition.setParentName("user");
childGenericBeanDefinition.setBeanClass(Person.class);
childGenericBeanDefinition.getPropertyValues().add("address", "上海市");
ctx.registerBeanDefinition("person", childGenericBeanDefinition);
User user = ctx.getBean(User.class);
Person person = ctx.getBean(Person.class);
System.out.println("user = " + user);
System.out.println("person = " + person);
}
结果:
user = User{id=4, name='gongj'}
person = Person{id=4, name='gongj', address='上海市'}
子接口:AnnotatedBeanDefinition
public interface AnnotatedBeanDefinition extends BeanDefinition {
AnnotationMetadata getMetadata();
@Nullable
MethodMetadata getFactoryMethodMetadata();
}
该接口可以返回两个元数据的类:
- AnnotationMetadata:主要对 Bean 的注解信息进行操作,如:获取当前 Bean 标注的所有注解、判断是否包含指定注解。
public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
default Set<String> getAnnotationTypes() {
return getAnnotations().stream()
.filter(MergedAnnotation::isDirectlyPresent)
.map(annotation -> annotation.getType().getName())
.collect(Collectors.toCollection(LinkedHashSet::new));
}
default Set<String> getMetaAnnotationTypes(String annotationName) {
MergedAnnotation<?> annotation = getAnnotations().get(annotationName, MergedAnnotation::isDirectlyPresent);
if (!annotation.isPresent()) {
return Collections.emptySet();
}
return MergedAnnotations.from(annotation.getType(), SearchStrategy.INHERITED_ANNOTATIONS).stream()
.map(mergedAnnotation -> mergedAnnotation.getType().getName())
.collect(Collectors.toCollection(LinkedHashSet::new));
}
default boolean hasAnnotation(String annotationName) {
return getAnnotations().isDirectlyPresent(annotationName);
}
default boolean hasMetaAnnotation(String metaAnnotationName) {
return getAnnotations().get(metaAnnotationName,
MergedAnnotation::isMetaPresent).isPresent();
}
default boolean hasAnnotatedMethods(String annotationName) {
return !getAnnotatedMethods(annotationName).isEmpty();
}
Set<MethodMetadata> getAnnotatedMethods(String annotationName);
static AnnotationMetadata introspect(Class<?> type) {
return StandardAnnotationMetadata.from(type);
}
}
- MethodMetadata:方法的元数据类。提供获取方法名称、此方法所属类的全类名、是否是抽象方法、判断是否是静态方法、判断是否是final方法等。
public interface MethodMetadata extends AnnotatedTypeMetadata {
String getMethodName();
String getDeclaringClassName();
String getReturnTypeName();
boolean isAbstract();
boolean isStatic();
boolean isFinal();
boolean isOverridable();
}
该接口下有三大子类: ScannedGenericBeanDefinition 、ConfigurationClassBeanDefinition 、AnnotatedGenericBeanDefinition
ScannedGenericBeanDefinition
实现了 AnnotatedBeanDefinition 也继承了 GenericBeanDefinition 。这个 BeanDefinition 用来描述标注@Component、@Service、@Controller 等注解标记的类会解析为ScannedGenericBeanDefinition 。
它的源码很简单,就是多了一个属性:metadata 用来存储扫描进来的Bean 的一些注解信息。
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
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;
}
}
验证
@Component、@Service、@Controller 等注解标记的类是否会解析为 ScannedGenericBeanDefinition
新建 AppConfig 类
@ComponentScan("com.gongj")
public class AppConfig {
}
然后再创建HelloController 类
@Controller
public class HelloController {
}
启动
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
BeanDefinition helloController = context.getBeanFactory().getBeanDefinition("helloController");
}
AnnotatedGenericBeanDefinition
该类继承自 GenericBeanDefinition ,并实现了AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述标注使用了@Configuration 注解标记配置类会解析为 AnnotatedGenericBeanDefinition 。
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
@Nullable
private MethodMetadata factoryMethodMetadata;
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = AnnotationMetadata.introspect(beanClass);
}
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;
}
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;
}
}
验证
新建 MyConfig 类
@Configuration
public class MyConfig {
}
启动
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
BeanDefinition myConfig = context.getBeanFactory().getBeanDefinition("myConfig");
}
如果使用 AppConfig 作为扫描包,MyConfig 的实际类型是 ScannedGenericBeanDefinition ,当然这个与启动有关,后面的博文再说。
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
BeanDefinition myConfig = context.getBeanFactory().getBeanDefinition("myConfig");
ConfigurationClassBeanDefinition
它是ConfigurationClassBeanDefinitionReader 的一个私有的静态内部类:这个类负责将@Bean 注解的方法转换为对应的ConfigurationClassBeanDefinition 类,源码就不过多解释了,和之前几个BeanDefinition 差不多。
其功能特点如下:
@Bean("mz")
public User myUserBean(){
return new User();
}
启动
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
BeanDefinition mz = context.getBeanFactory().getBeanDefinition("mz");
User myUserBean = (User)context.getBean("mz");
System.out.println("mz =" + mz);
System.out.println("myUserBean = " + myUserBean);
}
spring初始化时,会用GenericBeanDefinition或是ConfigurationClassBeanDefinition(用@Bean注解注释的类)存储用户自定义的Bean,在初始化Bean时,又会将其转换为RootBeanDefinition。
参考文献: 松哥:Spring 源码第四弹!深入理解 BeanDefinition
大佬:Spring IoC容器中核心定义之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition)
大佬:Spring(四)核心容器 - BeanDefinition 解析
大佬:Spring元数据Metadata的使用
|