问题:在项目里两次对同一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时通过属性设置上去。