网上写spring源码的文章很多,为什么我还想要再写一遍呢。有很重要的一点,就是每个人在阐述源码的时候侧重点不同。当我对spring的某一部分有疑惑的时候,去翻看别人写的博客,翻了很多篇,到后来才发现,我的疑惑依然没有得到解答。很大程度是因为别人写的标题就是我存在的问题,但是别人写的重点却不是我想要了解的点。于是大多数时候在网上看文章解决问题的过程就像是在点燃一个蔫炮。你搜索A问题的关键字,就好像双手颤颤着点燃了引信,然后你在A问题给出的解决方案里,发现B问题是解决A问题的前提,然后,你转头去着手解决B问题,而后还会冒出C问题,D问题。。。这个过程,就像引信在载着滋滋的火花将要送进炮膛。你以为顺着引信的尽头就是就一声巨响,所有的问题就会迎刃而解。但是很不幸,引信没了,炮却蔫了。。。时间花费了不少,但是,问题还是那个问题。。。
在经历过许多次这种反反复复的希望与失望的煎熬之后,我终于决定,我要从头开始,仔仔细细将阅读spring源码的整个过程记录下来,一是为了避免被同一个问题绊倒,同一条河趟两遍;二是,将我的观点发出来,与大家共同探讨改进,以弥补自己的不足。我不能保证我写的东西一定正确,我可以保证的是,我一定认真去写。
好,接下来,进入正题。
一、 BeanDefinition的作用
我们都知道Spring是一个Bean管理容器。他可以创建Bean,同时缓存Bean的实例。我们在需要某类的实例的时候,向Spring容器按需取用即可。而要了解这一切,我们首要认识的一个接口就是BeanDefinition接口。
BeanDefinition为什么这么重要呢?因为spring在创建一个Bean的时候,它会调用如下方法:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
.....;
}
繁琐的方法内容我们留在后边分析,这里先不看方法体。我们看创建一个Bean,都需要哪些“原材料”?原材料是以方法注入的形式提供给spring的,那么,框架都给方法中注入哪些内容呢? 第一是BeanName, BeanName大家都熟,用来标识我们要创建的是哪个bean;第三个参数args,对应你要创建的Bean的构造方法参数列表。这里可以为null(@Nullable),说明不论你提供的是有参的构造方法,还是无参构造方法,spring都能通过这个方法创建一个bean的实例并缓存之。
我们先来分析最简单的情况,无参构造创建Bean的实例, 如果说,beanName中只是一个String类型的创建Bean的标识符,而无参情况下,第三个参数为null的话,那么第二个参数RootBeanDefinition对创建Bean是至关重要的了。也就是说,一个RootBeanDefinition提供了创建Bean的关键信息。
下面重点分析第二个参数,这个与我们今天要说的BeanDefinition有什么样的关系呢?它继承关系如下。
RootBeanDefinition在创建Bean实例的时候会被使用到,而RootBeanDefinition这个类的规范由接口BeanDefinition界定。可以这么说,要想在Spring中创建Bean的实例,BeanDefinition必不可少。
那么,具体都规范了一些什么内容呢?
二、BeanDefinition详解
我们下边贴出BeanDefinition的源码来。每个方法的作用由注释给出,不再另外描述。
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
/**
* 常量SINGLETON,对应于该类的scope属性:
*/
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
/**
* 常量PROTOTYPE,对应于该类的scope属性:
*/
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
/**
*对应@Role注解使用,用户自己创建的Bean可以在创建的类上注明,@Role(ROLE_APPLICATION)
*/
int ROLE_APPLICATION = 0;
/**
* 对应@Role注解使用,用于支持功能类的注解
*/
int ROLE_SUPPORT = 1;
/**
*
* 对应@Role注解使用,用于框架内部使用类的注解
*/
int ROLE_INFRASTRUCTURE = 2;
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
/**
* 设置Bean的BeanName。
*/
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
/**
* 设置Scope
*/
void setScope(@Nullable String scope);
@Nullable
String getScope();
/**
* 是否进行懒加载。
*/
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
/**
* 传入是string类型的BeanName,传入的这些类将会优先当前类进行初始化。
*/
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
/**
* 设置自动注入时候的是否会使用该类。如果为false,则当前类不可以用于自动注入,
*/
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();
/**
* Return whether this a <b>Singleton</b>, with a single, shared instance
* returned on all calls.
* @see #SCOPE_SINGLETON
*/
boolean isSingleton();
/**
* Return whether this a <b>Prototype</b>, with an independent instance
* returned for each call.
* @since 3.0
* @see #SCOPE_PROTOTYPE
*/
boolean isPrototype();
/**
* Return whether this bean is "abstract", that is, not meant to be instantiated.
*/
boolean isAbstract();
@Nullable
String getResourceDescription();
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
三、BeanDefinition的主要作用
我们在spring以外的环境中,比如本地环境创建一个类的时候,只需要提供该类的.class文件就可以了。而在spring中要创建一个类,除了要提供class文件以外,还需要提供BeanDefinition中的这些属性。BeanDefinition规定的属性都是与spring容器相关的。比如它在Spring中的Scope是什么,是单例还是多例?容器加载它的时候是否需要懒加载等等,上边常用的属性我几乎都给出了注解,大家看注释应该能明白如何使用。
这里下个结论,一份BeanDefinition就像是一个类留给Spring的使用说明书。告知Spring如何去加载存储这个类。
一些补充说明:
需要多说几句的是:
@Primary 注解使用的地方在一个类声明的地方,当我们依赖注入使用@Autowired注解时,默认会按照类型进行寻找,如果同类型的类找到好几个都匹配的话,我们在其中一个类上边写@Primary,那么就会将写了@Primary注解的类进行注入。
Set/getDependOn注解与@DependOn注解对应,它主要用于有加载顺序要求的场景。在@DependOn修饰的类注册之前,需要将它参数列中的String[] 所对应的Bean进行实例化。
其他没什么好说的了。BeanDefinition比较简单,大家对关键的以及常用的属性做个了解就好。