问题:在项目里两次对同一dubbo客户端添加@Reference注解,导致注解属性不起效果。具体demo代码如下:
@Service
public class DemoService1Impl implements DemoService1 {
@Reference(url = "dubbo://127.0.0.1:12345",validation = "true",timeout = 50000)
private DemoService demoService;
@Override
public void test() {
demoService.sayHello("aaa");
}
}
@Service
public class DemoService2Impl implements DemoService2 {
@Reference(url = "dubbo://127.0.0.1:12345",validation = "false",timeout = 1000000)
private DemoService demoService;
@Override
public void test() {
demoService.sayHello("aaaa");
}
}
如果先注入了DemoService2Impl这个bean,在DemoService1Impl这个bean中注入的DemoService他的validation的值一直为false,引起原因,在dubbo2.7.3的版本,注入时会从缓存获取,但是缓存的key值是DemoService类的全名,所以导致再次注入时都是第一个注入的配置。好在dubbo的2.7.4版本已经修复该bug。
下面分析dubbo的@Reference注解注入原理:
一、spring的单列创建过程:
Spring下文的刷新方法refresh
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {try {// 这里单例的初始化方法入口
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
}
}
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// 实例化所有非懒加载单例
beanFactory.preInstantiateSingletons();
}
具体实现如下:
@Override
public void preInstantiateSingletons() throws BeansException {
//所有的bean
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//如果不是抽象 and 单列 and 非延迟初始化
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//如果继承FactoryBean的 判断工厂方法是否饥饿加载
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
//这里真正获取bean
getBean(beanName);
}
}
}
// 主要为调用afterSingletonsInstantiated的单例初始化后的操作
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
然后到getBean方法:
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
这里面好几种方式获取bean,真正调用的方法是doGetBean:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
}
else {
try {
// 如果是单例
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
//真正创建单例的方法
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//多例
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
//其他作用范围
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
return (T) bean;
}
这个方法看起来很复杂,最后真正创建的方法是AbstractAutowireCapableBeanFactory的createBean方法:
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
//执行postProcessBeforeInstantiation的地方
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
try {
//真正创建bean地方
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
}
上面我们用到的很多bean做拓展的地方resolveBeforeInstantiation这个方法:
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
获得注入的所有实现BeanPostProcessor接口的bean,依次调用。然后我们看真正创建bean的方法doCreateBean:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
//真正创建bean对象,并使用BeanWrapper包装
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
//这里是依次调用MergedBeanDefinitionPostProcessor的方法
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//填充bean的所有属性
populateBean(beanName, mbd, instanceWrapper);
//初始化bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
然后我们先分析populateBean方法:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
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;
}
}
}
}
这个方法很复杂,最后真正对属性赋值的是查找到所有继承InstantiationAwareBeanPostProcessor的bean 然后依次调用postProcessPropertyValues方法,而这里恰好就是dubbo拓展了的地方。
二、dubbo的@Refrence的注入过程:
在dubbo的自动配置DubboAutoConfiguration类中注入了:
@ConditionalOnMissingBean
@Bean(name = ReferenceAnnotationBeanPostProcessor.BEAN_NAME)
public ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor() {
return new ReferenceAnnotationBeanPostProcessor();
}
ReferenceAnnotationBeanPostProcessor 这个类继承了AnnotationInjectedBeanPostProcessor,而AnnotationInjectedBeanPostProcessor最终实现了InstantiationAwareBeanPostProcessor的postProcessPropertyValues方法:
在AnnotationInjectedBeanPostProcessor类中有如下方法:
@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;
}
最后调用了AnnotatedFieldElement的inject方法:
·@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Class<?> injectedType = field.getType();
//获取dubbo生成的代理对象
Object injectedObject = getInjectedObject(attributes, bean, beanName, injectedType, this);
ReflectionUtils.makeAccessible(field);
//设置到DemoService1Impl的demoService字段上
field.set(bean, injectedObject);
}
生成dubbo代理对象的核心方法getInjectedObject如下:
protected Object getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
//创建dubbo对象的缓存key
//最终生成的key="ServiceBean:com.donny.DemoService#source=private com.donny.DemoService com.donny.DemoService1Impl.demoService#attributes={timeout=50000, url=dubbo://127.0.0.1:12345, validation=true}"
String cacheKey = buildInjectedObjectCacheKey(attributes, bean, beanName, injectedType, injectedElement);
//缓存中是否存在
Object injectedObject = injectedObjectsCache.get(cacheKey);
if (injectedObject == null) {
//真正获取dubbo代理对象的方法
injectedObject = doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);
// Customized inject-object if necessary
injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
}
return injectedObject;
}
然后我们去到了ReferenceAnnotationBeanPostProcessor的doGetInjectedBean方法:
@Override
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
//referencedBeanName="ServiceBean:com.donny.DemoService"
String referencedBeanName = buildReferencedBeanName(attributes, injectedType);
//referenceBeanName="@Reference(timeout=50000,url=dubbo://127.0.0.1:12345,validation=true) com.donny.DemoService"
//这个是在2.7.4新加的名称,为了区分不同配置的@Refrence注解创建不同的实例
String referenceBeanName = getReferenceBeanName(attributes, injectedType);
//在2.7.3 buildReferenceBeanIfAbsent()传的是referencedBeanName
//创建dubbo的客户端ReferenceBean
ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referenceBeanName, attributes, injectedType);
//注册ReferenceBean到工厂
registerReferenceBean(referencedBeanName, referenceBean, attributes, injectedType);
cacheInjectedReferenceBean(referenceBean, injectedElement);
//创建dubbo的客户端代理bean
return getOrCreateProxy(referencedBeanName, referenceBeanName, referenceBean, injectedType);
}
然后我们再看下registerReferenceBean方法:
private void registerReferenceBean(String referencedBeanName, ReferenceBean referenceBean,
AnnotationAttributes attributes,
Class<?> interfaceClass) {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
String beanName = getReferenceBeanName(attributes, interfaceClass);
if (existsServiceBean(referencedBeanName)) { // If @Service bean is local one
/**
* Get the @Service's BeanDefinition from {@link BeanFactory}
* Refer to {@link ServiceAnnotationBeanPostProcessor#buildServiceBeanDefinition}
*/
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanFactory.getBeanDefinition(referencedBeanName);
RuntimeBeanReference runtimeBeanReference = (RuntimeBeanReference) beanDefinition.getPropertyValues().get("ref");
// The name of bean annotated @Service
String serviceBeanName = runtimeBeanReference.getBeanName();
// register Alias rather than a new bean name, in order to reduce duplicated beans
beanFactory.registerAlias(serviceBeanName, beanName);
} else { // Remote @Service Bean
if (!beanFactory.containsBean(beanName)) {
//最终注册到spring,beanName=“@Reference(timeout=50000,url=dubbo://127.0.0.1:12345,validation=true) com.donny.DemoService”
beanFactory.registerSingleton(beanName, referenceBean);
}
}
}
ReferenceBean包含了dubbo客户端的所有配置信息
由上可以总结出:dubbo的ReferenceBean会注册到spring,而dubbo的客户端代理bean不会注册到spring(使用@MockBean单元测试时dubbo客户端不能mock也是这个原因,只能手工mock后赋值),只是在创建spring的bean时通过属性设置上去。