日积月累,水滴石穿 😄
BeanDefinition
在 Spring
容器中,我们使用的是一个一个的 Bean,那在Spring
中,我们可以如何去定义一个 Bean?
bean标签
@Bean注解
@Component(@Service、@Controller)
除上述方式外,还有就是可以通过BeanDefinition
这个类,定义 Bean 对象。
比如,我们可以通过定义一个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) {
// 定义了一个BeanDefinition
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition()
.getBeanDefinition();
// 当前Bean对象的类型
beanDefinition.setBeanClass(User.class);
// 将BeanDefinition注册到BeanFactory中
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("user", beanDefinition);
// 获取Bean
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/>,@Bean
,@Component
等方式所定义的Bean,最终都会被解析为BeanDefinition
对象。要理解 BeanDefinition
,我们先从 BeanDefinition
的继承关系开始看起:
可以看到 BeanDefinition
是一个接口,继承自 BeanMetadataElement
和 AttributeAccessor
接口。
- AttributeAccessor:定义用于附加和访问元数据的通用协定的接口,可以是任意对象。具体的实现则是
AttributeAccessorSupport
,采用LinkedHashMap
进行存储。
public interface AttributeAccessor {
//设置属性的值(名称唯一)
void setAttribute(String name, Object value);
//获得指定属性名称的值,如果不存在返回null
Object getAttribute(String name);
//删除指定的name的属性,如果不存在则返回null
Object removeAttribute(String name);
//判断指定的属性名称是否存在
boolean hasAttribute(String name);
//返回所有属性的名称
String[] attributeNames();
}
- BeanMetadataElement:该接口只有一个方法 getSource,该方法返回 Bean 的来源。
这是 BeanDefinition
所继承的两个接口。接下来我们来看下 BeanDefinition
本身。
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 单例Bean还是原型Bean
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
// Bean角色
int ROLE_APPLICATION = 0; //用户自己定义的 Bean
int ROLE_SUPPORT = 1; //来源于配置文件的 Bean
int ROLE_INFRASTRUCTURE = 2;//Spring 内部的 Bean
//配置 /获取父BeanDefinition的名称 XML中的 <bean parent="">
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
//配置/获取 Bean 的 Class 全路径 XML 中的 <bean class="">
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
//配置/获取 Bean 的作用域 XML中的 <bean scope=""> 配置。
void setScope(@Nullable String scope);
@Nullable
String getScope();
//配置 / 获取 Bean 是否懒加载(默认false,立马加载)
// XML 中的 <bean lazy-init="">
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
//配置/获取 Bean 的依赖对象 XML中的 <bean depends-on="">
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
//配置/获取 Bean 是否是自动装配的候选者 默认为 true XML中的 <bean autowire-candidate="">
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
//如果找到了多个可注入bean,那么则选择被Primary标记的bean/获取当
//前 Bean 是否为首选的 Bean XML中的 <bean primary="">
void setPrimary(boolean primary);
boolean isPrimary();
// 配置/获取 FactoryBean 的名字 XML中的<bean factory-bean="">
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
//配置/获取 FactoryMethod 的名字,可以是某个实例的方法(和factoryBean配合使用)
//也可以是静态方法。 XML 中的<bean factory-method="">
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
//返回该 Bean 构造方法的参数值
ConstructorArgumentValues getConstructorArgumentValues();
//判断 getConstructorArgumentValues 是否是空对象。
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
//获取普通属性的集合
MutablePropertyValues getPropertyValues();
//判断 getPropertyValues 是否为空对象
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
// 配置/获取 Bean 的初始化方法 XML中的<bean init-method="">
void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();
// 配置/获取 Bean 的销毁方法 XML中的<bean destroy-method="">
void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();
//配置/获取 Bean的角色
void setRole(int role);
int getRole();
//配置/获取 Bean 的描述
void setDescription(@Nullable String description);
@Nullable
String getDescription();
//用来解析一个Bean对应的类型上的各种信息,比如泛型
ResolvableType getResolvableType();
//是否为单例
boolean isSingleton();
// 是否为原型
boolean isPrototype();
//是否抽象 XML 中的<bean abstract="true">
boolean isAbstract();
//返回定义 Bean 的资源描述
@Nullable
String getResourceDescription();
// 如果当前 BeanDefinition 是一个代理对象,那么该方法可以用来返回原始的 BeanDefinition
@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 = "";
//自动装配的一些常量
// autowireMode = 0,默认值,未激活Autowiring。
// bean 标签的 autowire 属性值为 no
// 1、在xml中需要手动指定依赖注入对象 配置 property标签或者 constructor-arg标签
// 2、使用 @Autowired 注解,autowireMode 的值也是 0
public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
//autowireMode = 1,根据set方法的的名称作为Bean名称进行依赖查找
//(去掉set,并尝试将首字母变为小写),并将对象设置到该set方法的参数上
// bean 标签的 autowire 属性值配置为 byName
public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
//autowireMode = 2,根据set方法参数的类型作为Bean类型进行依赖查找
//并将对象设置到该set方法的参数上
// bean 标签的 autowire 属性值配置为 byType
public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
//autowireMode = 3,构造器注入
// bean 标签的 autowire 属性值配置为 constructor
public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
//表明通过Bean的class的内部来自动装配 Spring3.0被弃用。
// bean 标签的 autowire 属性值配置为 autodetect
@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;
//若Bean未指定销毁方法,容器应该尝试推断Bean的销毁方法的名字,
//目前,推断的销毁方法的名字一般为close或是shutdown
public static final String INFER_METHOD = "(inferred)";
//Bean的class对象或是类的全限定名
@Nullable
private volatile Object beanClass;
//默认的scope是单例,对应bean属性scope
//@Scope
@Nullable
private String scope = SCOPE_DEFAULT;
//是否是抽象,对应bean属性abstract
private boolean abstractFlag = false;
//是否懒加载,对应bean属性lazy-init,默认不是懒加载
//@Lazy
@Nullable
private Boolean lazyInit;
//自动注入模式,对应bean属性autowire,默认不进行自动装配
private int autowireMode = AUTOWIRE_NO;
//是否进行依赖检查,默认不进行依赖检查
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
//用来表示一个bean的实例化是否依靠另一个bean的实例化,先加载dependsOn的bean,
//对应bean属性depend-on
//@DependsOn
@Nullable
private String[] dependsOn;
/**
* autowire-candidate属性设置为false,这样容器在查找自动装配对象时,
* 将不考虑该bean,即它不会被考虑作为其他bean自动装配的候选者,
* 但是该bean本身还是可以使用自动装配来注入其他bean的
*/
private boolean autowireCandidate = true;
/**
* 自动装配时出现多个bean候选者时,将作为首选者,对应bean属性primary,默认不是首选的
* @Primary
*/
private boolean primary = false;
/**
* 用于记录Qualifier,对应子元素qualifier <bean><qualifier></qualifier></bean>
* 如果容器中有多个相同类型的 bean,这时我们就可以使用qualifier属性来设置加载指定Bean名称的bean
* @Qualifier
*/
private final Map < String, AutowireCandidateQualifier > qualifiers = new LinkedHashMap <>();
//java8的函数式接口,创建bean实例的方式之一
@Nullable
private Supplier <? > instanceSupplier;
//是否允许访问非public方法和属性, 默认是true
private boolean nonPublicAccessAllowed = true;
/**
* 是否以一种宽松的模式解析构造函数,默认为true,
* 如果为false,则在以下情况
* interface ITest{}
* class ITestImpl implements ITest{};
* class Main {
* Main(ITest i) {}
* Main(ITestImpl i) {}
* }
* 抛出异常,因为Spring无法准确定位哪个构造函数程序设置
*/
private boolean lenientConstructorResolution = true;
//工厂类名,对应bean属性factory-bean
@Nullable
private String factoryBeanName;
//工厂方法名,对应bean属性factory-method
@Nullable
private String factoryMethodName;
//记录构造函数注入属性,对应bean属性constructor-arg
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
//Bean属性的名称以及对应的值,这里不会存放构造函数相关的参数值,只会存放通过setter注入的值
@Nullable
private MutablePropertyValues propertyValues;
//方法重写的持有者,记录lookup-method、replaced-method元素 @Lookup
private MethodOverrides methodOverrides = new MethodOverrides();
//初始化方法,对应bean属性init-method
@Nullable
private String initMethodName;
//销毁方法,对应bean属性destroy-method
@Nullable
private String destroyMethodName;
//是否执行init-method,默认为true
private boolean enforceInitMethod = true;
//是否执行destroy-method,默认为true
private boolean enforceDestroyMethod = true;
//是否是用户定义的而不是应用程序本身定义的,创建AOP时候为true
private boolean synthetic = false;
//Bean的角色,为用户自定义Bean
private int role = BeanDefinition.ROLE_APPLICATION;
//Bean的描述信息
@Nullable
private String description;
//这个bean定义的资源
@Nullable
private Resource resource;
//...
}
RootBeanDefinition
这是一个最常用的实现类,Spirng
去创建 Bean
时是基于RootBeanDefinition
去创建的!
RootBeanDefinition
继承了AbstractBeanDefinition
,在AbstractBeanDefinition
的基础上扩展了一些之外的功能,并且RootBeanDefinition
是没有父BeanDefinition
的。
public class RootBeanDefinition extends AbstractBeanDefinition {
// BeanDefinitionHolder 存储 Bean 的名称、别名、BeanDefinition
@Nullable
private BeanDefinitionHolder decoratedDefinition;
// AnnotatedElement 是java反射包的接口,通过它可以查看 Bean 的注解信息
@Nullable
private AnnotatedElement qualifiedElement;
// 决定了什么时候 BeanDefinition 需要重新合并
volatile Boolean stale;
// 允许缓存
Boolean allowCaching = true;
// 工厂方法是否唯一
Boolean isFactoryMethodUnique = false;
//封装了 java.lang.reflect.Type,提供了泛型相关的操作
@Nullable
volatile ResolvableType targetType;
//用于缓存给定bean定义中确定的类
// 表示 RootBeanDefinition 存储哪个类的信息
@Nullable
volatile Class<?> resolvedTargetType;
//如果bean是FactoryBean,则用于缓存
@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();
//这表明已经应用了MergedBeanDefinitionPostProcessor
Boolean postProcessed = false;
//表明一个实例化前的后处理器已经启动
@Nullable
volatile Boolean beforeInstantiationResolved;
//实际缓存的类型是 Constructor、Field、Method 类型
@Nullable
private Set<Member> externallyManagedConfigMembers;
// InitializingBean中 的 init 回调函数名 afterPropertiesSet 会在这里记录,以便进行生命周期回调
@Nullable
private Set<String> externallyManagedInitMethods;
// DisposableBean 的 destroy 回调函数名 destroy 会在这里记录,以便进生命周期回调
@Nullable
private Set<String> externallyManagedDestroyMethods;
//===========贴一个方法
// 很明显,RootBeanDefiniiton是没有父BeanDefinition
@Override
public String getParentName() {
return null;
}
// 并且还不能进行set
@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();
//属性的集合 在其父类 AbstractBeanDefinition 已经提到过了
MutablePropertyValues mpvs = new MutablePropertyValues();
mpvs.add("id",4L);
mpvs.add("name","gongj");
//BeanDefinition
RootBeanDefinition rootBeanDefinition =new RootBeanDefinition(User.class,null,mpvs);
//注册到Spring容器中
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();
//普通属性的集合 在其父类 AbstractBeanDefinition 已经提到过了
MutablePropertyValues mpvs = new MutablePropertyValues();
mpvs.add("id",4L);
mpvs.add("name","gongj");
//RootBeanDefinition
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class,null,mpvs);
//注册到Spring容器中
context.registerBeanDefinition("user",rootBeanDefinition);
// ChildBeanDefinition 开始
MutablePropertyValues childValues = new MutablePropertyValues();
childValues.add("address","上海市");
//通过构造方法传入父 BeanDetintion 的名称
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();
//普通属性的集合 在其父类 AbstractBeanDefinition 已经提到过了
MutablePropertyValues mpvs = new MutablePropertyValues();
mpvs.add("id",4L);
mpvs.add("name","gongj");
GenericBeanDefinition parentGenericBeanDefinition = new GenericBeanDefinition();
parentGenericBeanDefinition.setBeanClass(User.class);
parentGenericBeanDefinition.setPropertyValues(mpvs);
//注册到Spring容器中
ctx.registerBeanDefinition("user",parentGenericBeanDefinition);
GenericBeanDefinition childGenericBeanDefinition = new GenericBeanDefinition();
//设置父BeanDefinition的名称
childGenericBeanDefinition.setParentName("user");
childGenericBeanDefinition.setBeanClass(Person.class);
childGenericBeanDefinition.getPropertyValues().add("address", "上海市");
//注册到Spring容器中
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
//关于其bean类-无需加载该类。
public interface AnnotatedBeanDefinition extends BeanDefinition {
//获取此bean定义注解的元数据
AnnotationMetadata getMetadata();
//获取此bean定义的工厂方法的元数据,如果没有,则为null
@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));
}
//获得annottationName对应的元注解的类全限定名
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();
}
//类里面只要有一个方法标注有指定注解,就返回true
default boolean hasAnnotatedMethods(String annotationName) {
return !getAnnotatedMethods(annotationName).isEmpty();
}
// 返回所有的标注有指定注解的方法元信息
Set<MethodMetadata> getAnnotatedMethods(String annotationName);
//工厂方法来使用标准反射为给定的类创建一个新的AnnotationMetadata实例
static AnnotationMetadata introspect(Class<?> type) {
return StandardAnnotationMetadata.from(type);
}
}
- MethodMetadata:方法的元数据类。提供获取方法名称、此方法所属类的全类名、是否是抽象方法、判断是否是静态方法、判断是否是final方法等。
public interface MethodMetadata extends AnnotatedTypeMetadata {
//返回方法的名字
String getMethodName();
//返回该方法所属的类的全限定名
String getDeclaringClassName();
//返回该方法返回类型的全限定名
String getReturnTypeName();
//方法是否是有效的抽象方法:即在类上标记为抽象的或声明为规则的,
//接口中的非默认方法。
boolean isAbstract();
//方法是否声明为'static'。
boolean isStatic();
//方法是否标记为'final'。
boolean isFinal();
//方法是否可重写:即没有标记为static、final或private。
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;
/**
* 鉴于MetadataReader描述,为类创建一个新的ScannedGenericBeanDefinition
*/
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;
/**
* 为给定的bean类创建一个新的AnnotatedGenericBeanDefinition
* @param beanClass the loaded bean class:加载的bean类
*/
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
// 当前类上有哪些注解
this.metadata = AnnotationMetadata.introspect(beanClass);
}
/**
*
* 为给定的注释元数据创建一个新AnnotatedGenericBeanDefinition,传入AnnotationMetadata
*/
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;
}
/**
*
* 基于一个带注解的类和该类上的工厂方法。,为给定的注释元数据创建一个新的AnnotatedGenericBeanDefinition,
*/
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
差不多。
其功能特点如下:
- 1、如果
@Bean
注解没有指定 Bean 的名字,默认会用方法的名字作为Bean的名称。 2、标注
@Configuration、@Component、@Service
注解的类会成为一个工厂类,而标注@Bean
注解的方法会成为工厂方法,通过工厂方法实例化 Bean。验证
在
MyConfig
类中新增方法:
@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。