問題:在項目里兩次對同一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時通過屬性設置上去。