Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
说到Bean的实例化,就不得不提一下InstantiationAwareBeanPostProcessor接口。 InstantiationAwareBeanPostProcessor继承自BeanPostProcessor接口。
InstantiationtiationAwareBeanPostProcessor接口的方法介绍:
1.postProcessBeforeInstantiation方法是最先执行的方法,它在目标对象实例化之前调用,该方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走
2.postProcessAfterInstantiation方法在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。因为它的返回值是决定要不要调用postProcessPropertyValues方法的其中一个因素(因为还有一个因素是mbd.getDependencyCheck());如果该方法返回false,并且不需要check,那么postProcessPropertyValues就会被忽略不执行;如果返回true,postProcessPropertyValues就会被执行
3.postProcessPropertyValues方法对属性值进行修改(这个时候属性值还未被设置,但是我们可以修改原本该设置进去的属性值)。如果postProcessAfterInstantiation方法返回false,该方法可能不会被调用。可以在该方法内对属性值进行修改。
BeanPostProcessor接口方法介绍:
1.postProcessBeforeInitialization方法是在bean初始化方法调用之前执行此方法。
2.postProcessAfterInitialization方法是在init-method方法执行之后执行。
在dubbo框架中的应用
dubbo服务的消费者,会引用服务提供方的接口,这个接口的实现类对象是通过动态代理生成的,其生成和注入的过程是正是利用了spring的InstantiationAwareBeanPostProcessor接口。
在AnnotationInjectedBeanPostProcessor类中,重写了postProcessPropertyValues()方法。对@Reference注解标注的属性,进行了赋值。
我们先写一个dubbo的服务的消费者。
@Service
public class ConsumerServiceImpl implements ConsumerService{
@Reference(check = false)
private AService aService;
@Override
public void invokeDubboApi(){
aService.test();
}
}
下面解析下源码,看下aService是如何赋值的。
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
//获取需要注入的属性和方法元数据
InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
try {
//注入属性值
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName()
+ " dependencies is failed", ex);
}
return pvs;
}
对于标注了@Reference注解的属性来说,使用如下代码进行属性值的注入:
public class AnnotatedFieldElement extends InjectionMetadata.InjectedElement {
private final Field field;
private final AnnotationAttributes attributes;
private volatile Object bean;
protected AnnotatedFieldElement(Field field, AnnotationAttributes attributes) {
super(field, null);
this.field = field;
this.attributes = attributes;
}
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Class<?> injectedType = field.getType();
//代理对象
Object injectedObject = getInjectedObject(attributes, bean, beanName, injectedType, this);
ReflectionUtils.makeAccessible(field);
//对属性赋值
field.set(bean, injectedObject);
}
}
inject方法很简单,就是先获取dubbo服务生产者的代理对象,然后利用反射进行赋值。
代理对象的生成详解,我将在下一篇文章中进行解说。
最后谢谢大家的支持,喜欢的话,请点赞关注哦。