前言
如果不是通过构造方法进行属性赋值的话,那实例化的对象中的属性的值都是 null ,所以这篇我们来看看 Spring
是如何给对象中的属性赋值的。
populateBean
方法位于 AbstractAutowireCapableBeanFactory
类。
populateBean 方法传入三个参数:
- beanName:bean名称
- mdb:当前bean的定义
- bw:当前实例的包装对象
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 没有实例化对象
if(bw == null) {
// 如果有为此bean定义属性值,则抛出异常
if(mbd.hasPropertyValues()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Cannot apply property values to null instance");
} else {
//直接返回,结束该方法
return;
}
}
// 可以提供InstantiationAwareBeanPostProcessor,控制对象的属性注入
// 我们可以自己写一个InstantiationAwareBeanPostProcessor,然后重写
// postProcessAfterInstantiation方法返回false
// 那么则不会进行属性填充了,直接返回
//isSynthetic():bena 不是"合成"的,即未由应用程序本身定义
// 是否持有 InstantiationAwareBeanPostProcessor
if(!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for(BeanPostProcessor bp: getBeanPostProcessors()) {
if(bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (
InstantiationAwareBeanPostProcessor) bp;
// postProcessAfterInstantiation:实例化后,该方法默认返回true
// 如果我们实现InstantiationAwareBeanPostProcessor,
// 然后重写postProcessAfterInstantiation方法返回false
// 将会阻止 Bean 的属性填充
if(!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(),
beanName)) {
return;
}
}
}
}
// 是否在BeanDefinition中设置了属性值
// xml中 property 属性的解析
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() :
null);
// autowire属性
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 这里取的是xml中 autowire 属性配置的值 如果是byType(2)、byName(1),就会进入这段逻辑
// 如果是使用 @Autowired,resolvedAutowireMode的值为 0
if(resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode ==
AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// byName
if(resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
//byType
if(resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
// by_name是根据set方法名字找bean
// by_type是根据所对应的set方法的参数类型找bean
// 找到bean之后都要调用set方法进行注入
// 注意,执行完这里的代码之后,这是把属性以及找到的值存在了pvs里面,并没有完成反射赋值
}
// 执行完了Spring的自动注入之后,就开始解析@Autowired、@Resource、@Value 等等注解
// 是否有InstantiationAwareBeanPostProcessor
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否进行依赖检查,默认不进行依赖检查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition
.DEPENDENCY_CHECK_NONE);
// @Autowired、@Value注解被AutowiredAnnotationBeanPostProcessor处理解析
// @Resource 注解被CommonAnnotationBeanPostProcessor处理解析
//这个两个类都是 InstantiationAwareBeanPostProcessor 接口的具体实现
PropertyDescriptor[] filteredPds = null;
if(hasInstAwareBpps) {
if(pvs == null) {
pvs = mbd.getPropertyValues();
}
for(BeanPostProcessor bp: getBeanPostProcessors()) {
if(bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (
InstantiationAwareBeanPostProcessor) bp;
// 调用BeanPostProcessor分别解析@Autowired、@Resource、@Value 等等注解,得到属性值
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(),
beanName);
if(pvsToUse == null) {
if(filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd
.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(),
beanName);
if(pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if(needsDepCheck) {
if(filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if(pvs != null) {
// pvs存的就是属性已经对应的值
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
复制代码
我们先来看一下autowireByName
方法,根据byName
寻找 Bean。
autowireByName 装配
准备一个 B 类,类中提供 setOrder方法、setORder
方法还有一个OrderService
属性。
public class B {
OrderService orderService;
public void setOrder(OrderService order){
System.out.println("setOrder = " +order);
}
public void setORder(OrderService order){
System.out.println("setORder = " + order);
}
}
public class OrderService {
}
//配置
<bean class="com.gongj.populateBean.OrderService" id="order"/>
// 根据byName 注入属性
<bean class="com.gongj.populateBean.B" id="b" autowire="byName"/>
启动类 main 方法:
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("spring-config2.xml");
打印结果:setOrder = com.gongj.populateBean.OrderService@6bf2d08e
复制代码
根据 byName
自动注入,执行的是 setOrder
方法,而不是 setORder
方法。Spring
是如何去寻找的呢?跟着小杰一起来揭开这神秘的面纱吧!
autowireByName 源码解析
protected void autowireByName(String beanName, AbstractBeanDefinition mbd,
BeanWrapper bw, MutablePropertyValues pvs) {
// 获得当前实例作用域为 public 的 set方法名称(去掉set)
//比如 setOrder -》 order
//setORder -》 ORder
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
//循环得到的名称
for(String propertyName: propertyNames) {
//判断名称在单例池(singletonObjects)中是否存在 或者 在beanDefinitionMap中是否存在
if(containsBean(propertyName)) {
// 根据名称直接去找bean,这就是byName
Object bean = getBean(propertyName);
// 将属性名称、属性值添加到pvs中
pvs.add(propertyName, bean);
//注册依赖Bean
registerDependentBean(propertyName, beanName);
if(logger.isTraceEnabled()) {
logger.trace("Added autowiring by name from bean name '" + beanName +
"' via property '" + propertyName + "' to bean named '" +
propertyName + "'");
}
} else {
if(logger.isTraceEnabled()) {
logger.trace("Not autowiring property '" + propertyName +
"' of bean '" + beanName + "' by name: no matching bean found");
}
}
}
}
复制代码
可以看到 setOrder
方法被去掉了 set 之后变为了 order
,O
由大写变为了小写 o
;而setORder
方法被去掉了 set 之后变为了ORder
,原样返回了。
处理流程
autowireByName
的处理流程:
1、获得所有公开的 set 方法(也会获取到父类的)。如果 set 方法的名称是 setOrder
,返回的就是order
,如果 set 方法的名称是 setORder
,返回就是ORder
。
2、循环获得的名称,先判断在容器中是否已经存在,存在就调用 getBean
方法,可以进行创建也可能直接获取。
3、将获得的对象赋值给 pvs,key 为 获得的名称,value为找到的对象。
4、注册依赖
下面就分别简单的分析一下各个流程:
1、unsatisfiedNonSimpleProperties
获得当前实例所有公开的(包括父类) set 方法,有如下几种情况:
1、无返回值的set有参方法(只能是一个参数),示例:
public void setOrderService(OrderService order){}
2、无参有返回值的get方法(返回类型不能是void),示例:
public String getba(){ return null;}
3、返回值为boolean类型的is无参方法,示例:
public boolean isDel(){return false;}
复制代码
OK,继续往下看。。。
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd,
BeanWrapper bw) {
Set <String> result = new TreeSet < > ();
// 获得在BeanDefinition中添加的属性值
PropertyValues pvs = mbd.getPropertyValues();
// 获得当前实例的所有公开的(包括父类) get、set 方法
// 一个方法就是一个 PropertyDescriptor 对象
// PropertyDescriptor 这个类已经不是 Spring 的类,它属于java.beans包下
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
// 对找到的属性进行过滤,确定哪些属性是需要进行自动装配的
for(PropertyDescriptor pd: pds) {
// 属性有set方法,getWriteMethod就不会为 null
// 并且没有通过DependencyCheck排除
// 并且没有在BeanDefinition中给该属性赋值
// 并且属性的类型不是简单类型
if(pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !
pvs.contains(pd.getName()) && !BeanUtils.isSimpleProperty(pd.getPropertyType())
) {
result.add(pd.getName());
}
}
// 将集合转换为数组
// 返回过滤之后的结果,后续只对这些属性进行自动装配
return StringUtils.toStringArray(result);
}
复制代码
getPropertyDescriptors
方法所返回的 PropertyDescriptor
是 java 的对象。这已经不是 Spring 的了。
这里也简单的贴一下吧!如果一直DEBUG
会进入到 Introspector
类的 getBeanInfo
方法。这个类是java
的类。
public static BeanInfo getBeanInfo(Class<?> beanClass)
throws IntrospectionException
{
if (!ReflectUtil.isPackageAccessible(beanClass)) {
return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
}
ThreadGroupContext context = ThreadGroupContext.getContext();
BeanInfo beanInfo;
synchronized (declaredMethodCache) {
beanInfo = context.getBeanInfo(beanClass);
}
if (beanInfo == null) {
// 看这里 new Introspector(beanClass, null, USE_ALL_BEANINFO) 这个构造方法里就有获取父类的逻辑,构造方法执行完毕之后,调用 getBeanInfo 方法
beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo();
synchronized (declaredMethodCache) {
context.putBeanInfo(beanClass, beanInfo);
}
}
return beanInfo;
}
复制代码
getBeanInfo
private BeanInfo getBeanInfo() throws IntrospectionException {
BeanDescriptor bd = getTargetBeanDescriptor();
MethodDescriptor mds[] = getTargetMethodInfo();
EventSetDescriptor esds[] = getTargetEventInfo();
//这里我们只看这个方法,很熟悉了吧
PropertyDescriptor pds[] = getTargetPropertyInfo();
int defaultEvent = getTargetDefaultEventIndex();
int defaultProperty = getTargetDefaultPropertyIndex();
return new GenericBeanInfo(bd, esds, defaultEvent, pds,
defaultProperty, mds, explicitBeanInfo);
}
复制代码
getTargetPropertyInfo
private PropertyDescriptor[] getTargetPropertyInfo() {
PropertyDescriptor[] explicitProperties = null;
if(explicitBeanInfo != null) {
explicitProperties = getPropertyDescriptors(this.explicitBeanInfo);
}
if(explicitProperties == null && superBeanInfo != null) {
// We have no explicit BeanInfo properties. Check with our parent.
addPropertyDescriptors(getPropertyDescriptors(this.superBeanInfo));
}
for(int i = 0; i < additionalBeanInfo.length; i++) {
addPropertyDescriptors(additionalBeanInfo[i].getPropertyDescriptors());
}
if(explicitProperties != null) {
// Add the explicit BeanInfo data to our results.
addPropertyDescriptors(explicitProperties);
} else {
// 看这里
// 获得当前类所有公开的方法
Method methodList[] = getPublicDeclaredMethods(beanClass);
for(int i = 0; i < methodList.length; i++) {
Method method = methodList[i];
if(method == null) {
continue;
}
//如果当前方法是 static 的,则跳过
int mods = method.getModifiers();
if(Modifier.isStatic(mods)) {
continue;
}
// 方法名称
String name = method.getName();
// 方法的参数类型
Class <? > [] argTypes = method.getParameterTypes();
// 方法的返回类型
Class <? > resultType = method.getReturnType();
// 方法的参数个数
int argCount = argTypes.length;
PropertyDescriptor pd = null;
// 如果方法名称的长度小于等于3,也就是说你的方法名称叫 set() get()
// 并且你的方法名不是以 is 开头的 则跳过当前方法
if(name.length() <= 3 && !name.startsWith(IS_PREFIX)) {
// Optimization. Don't bother with invalid propertyNames.
continue;
}
try {
// 如果参数个数为 0 ,也就是无参
if(argCount == 0) {
// 方法名称以 get 开头
if(name.startsWith(GET_PREFIX)) {
// 构建一个 PropertyDescriptor 对象
// name.substring(3) 这里截取了 get 这个三个字
pd = new PropertyDescriptor(this.beanClass, name.substring(3),
method, null);
}
// 如果返回类型是 boolean 并且 方法名称以 is 开头
else if(resultType == boolean.class && name.startsWith(IS_PREFIX)) {
// 构建一个 PropertyDescriptor 对象
// name.substring(2) 这里截取了 is 这个两个字
pd = new PropertyDescriptor(this.beanClass, name.substring(2),
method, null);
}
}
// 如果参数个数为1
else if(argCount == 1) {
if(int.class.equals(argTypes[0]) && name.startsWith(GET_PREFIX)) {
// 不管,这是 PropertyDescriptor 的子类
pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(
3), null, null, method, null);
}
// 如果返回类型是 void 并且 方法名称以 set 开头
else if(void.class.equals(resultType) && name.startsWith(SET_PREFIX)) {
// 构建一个 PropertyDescriptor 对象
// name.substring(3) 这里截取了 set 这个三个字
pd = new PropertyDescriptor(this.beanClass, name.substring(3),
null, method);
if(throwsException(method, PropertyVetoException.class)) {
pd.setConstrained(true);
}
}
}
// 如果参数个数为2
else if(argCount == 2) {
if(void.class.equals(resultType) && int.class.equals(argTypes[0]) &&
name.startsWith(SET_PREFIX)) {
pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(
3), null, null, null, method);
if(throwsException(method, PropertyVetoException.class)) {
pd.setConstrained(true);
}
}
}
} catch(IntrospectionException ex) {
pd = null;
}
if(pd != null) {
if(propertyChangeSource) {
pd.setBound(true);
}
addPropertyDescriptor(pd);
}
}
}
processPropertyDescriptors();
PropertyDescriptor result[] = properties.values().toArray(new PropertyDescriptor[
properties.size()]);
if(defaultPropertyName != null) {
for(int i = 0; i < result.length; i++) {
if(defaultPropertyName.equals(result[i].getName())) {
defaultPropertyIndex = i;
}
}
}
return result;
}
复制代码
看完上面这个方法,可以知道 PropertyDescriptor
存的可以是