Spring整合Dubbo中@Reference注解決議原理
@Reference: 可以用在屬性或者方法, 意味著需要參考某個Dubbo服務, 那么Dubbo整合Spring后, 我很好奇怎么把這個程序完成的,
package org.apache.dubbo.demo.provider;
public class Application {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
context.start();
System.in.read();
}
@Configuration
@EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
@PropertySource("classpath:/spring/dubbo-provider.properties")
static class ProviderConfiguration {
}
}
//@EnabeDubbo注解
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
//該屬性的值也是DubboComponentScan屬性basePackages的值;
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
boolean multipleConfig() default true;
}
- @DubboComponentScan: 用來掃描@Service 和@Reference注解修飾的類;
DubboComponentScanRegistrar
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
System.out.println("執行DubboComponentScanRegistrar");
// 拿到DubboComponentScan注解所定義的包路徑,掃描該package下的類,識別這些類上
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
// 注冊ServiceAnnotationBeanPostProcessor一個Bean
// 實作了BeanDefinitionRegistryPostProcessor介面,所以在Spring啟動時會呼叫postProcessBeanDefinitionRegistry方法
// 該方法會進行掃描,掃描@Service注解了的類,然后生成BeanDefinition(會生成兩個,一個普通的bean,一個ServiceBean),后續的Spring周期中會生成Bean
// 在ServiceBean中會監聽ContextRefreshedEvent事件,一旦Spring啟動完后,就會進行服務匯出
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
// 注冊ReferenceAnnotationBeanPostProcessor
// 實作了AnnotationInjectedBeanPostProcessor介面,繼而實作了InstantiationAwareBeanPostProcessorAdapter介面
// 所以Spring在啟動時,在對屬性進行注入時會呼叫AnnotationInjectedBeanPostProcessor介面中的postProcessPropertyValues方法
// 在這個程序中會按照@Refrence注解的資訊去生成一個RefrenceBean物件
registerReferenceAnnotationBeanPostProcessor(registry);
}
}
- registerServiceAnnotationBeanPostProcessor方法用來決議@Service注解修飾的類, 最后會獲得一個服務實作類, 一個ServiceBean類注入容器;
- registerReferenceAnnotationBeanPostProcessor: 是用來決議@Reference注解的方法;
registerReferenceAnnotationBeanPostProcessor(registry)
/**
* Registers {@link ReferenceAnnotationBeanPostProcessor} into {@link BeanFactory}
*
* @param registry {@link BeanDefinitionRegistry}
*/
private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {
// Register @Reference Annotation Bean Processor
// 注冊一個ReferenceAnnotationBeanPostProcessor做為bean,ReferenceAnnotationBeanPostProcessor是一個BeanPostProcessor
BeanRegistrar.registerInfrastructureBean(registry,
ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
}
作業:
- 判斷容器中是否包含了referenceAnnotationBeanPostProcessor名稱的Bean,如果有,結束;
- 根據Bean的型別ReferenceAnnotationBeanPostProcessor.class,創建一個RootBeanDefinition實體;
- 設定Role屬性;
- 注入容器中;
public class BeanRegistrar {
/**
* Register Infrastructure Bean
*
* @param beanDefinitionRegistry {@link BeanDefinitionRegistry}
* @param beanType the type of bean
* @param beanName the name of bean
*/
public static void registerInfrastructureBean(BeanDefinitionRegistry beanDefinitionRegistry,
String beanName,
Class<?> beanType) {
if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
}
}
}
ReferenceAnnotationBeanPostProcessor
- 繼承了AnnotationInjectedBeanPostProcessor類,該類又繼承了MergedBeanDefinitionPostProcessor,InstantiationAwareBeanPostProcessorAdapter 類;
- 應用啟動的時候, 對于我們引入服務的類, Spring會進行對這些類進行依賴注入(類似@Autowired)
- 依賴注入的時候會呼叫AnnotationInjectedBeanPostProcessor#postProcessPropertyValues()方法,這個方法里面使用了子類的處理邏輯,按照子類的處理邏輯進行依賴注入;
- 在依賴注入前,會先執行MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition方法, 子類AnnotationInjectedBeanPostProcessor實作了這個介面, 目的是掃描所有被@Reference注解修飾的方法和屬性的準備作業;
public class ReferenceAnnotationBeanPostProcessor extends AnnotationInjectedBeanPostProcessor implements
ApplicationContextAware, ApplicationListener {
//...
}
public abstract class AnnotationInjectedBeanPostProcessor extends
InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered,
BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean {
//...
}
public abstract class InstantiationAwareBeanPostProcessorAdapter implements SmartInstantiationAwareBeanPostProcessor {
//....
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
}
MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition方法
由子類AnnotationInjectedBeanPostProcessor 實作了這個方法;
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor
void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
}
public abstract class AnnotationInjectedBeanPostProcessor extends
InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered,
BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean {
//...
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType != null) {
InjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
}
}
一、findInjectionMetadata(beanName, beanType, null)
private InjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
try {
metadata = buildAnnotatedMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
} catch (NoClassDefFoundError err) {
//...
}
}
}
return metadata;
}
- 這些元資料是通過反射獲取的,由于反射本身性能不高,所以拿到一些元資料后,需要放入本地快取injectionMetadataCache中,下次直接從快取中獲取;
- 掃描 @Reference修飾的屬性或者方法,對應型別為AnnotatedFieldElement, AnnotatedMethodElement
- injectionMetadataCache快取 的 key為 bean的名稱,或者類的名稱, 值的型別AnnotatedInjectionMetadata;
- AnnotatedInjectionMetadata里面包裝兩個集合, 被@reference修飾的屬性集合, 被@Reference修飾的方法集合
buildAnnotatedMetadata(clazz)
作業:
- 獲取哪些Filed上有@Reference注解
- 獲取哪些方法上有@Reference注解
- 創建一個AnnotatedInjectionMetadata實體, 引數是屬性和方法集合, 屬性注入會按照這個類去進行的;回傳實體;
private AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
// 掃描Field
Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
// 掃描Method
Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
// 回傳的是Dubbo定義的AnnotatedInjectionMetadata,接下來就會使用這個類去進行屬性注入
return new AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
}
-
掃描Field
作業: -
創建結果集合List;
-
遍歷beanClass的所有的Field;
-
獲取Feild上所有的注解;
-
getMergedAttributes獲取@Reference注解, 如果不存在,回傳空;
-
存在@Reference注解,就會獲取@reference注解的所有屬性,AnnotationAttributes 存盤就是注解的屬性資訊;
-
存在Reference注解,就加入集合List;
private List<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> findFieldAnnotationMetadata(final Class<?> beanClass) {
final List<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> elements = new LinkedList<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement>();
ReflectionUtils.doWithFields(beanClass, field -> {
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
AnnotationAttributes attributes = getMergedAttributes(field, annotationType, getEnvironment(), true);
if (attributes != null) {
//...
elements.add(new AnnotatedFieldElement(field, attributes));
}
}
});
return elements;
}
- 掃描Method
作業:
- 創建結果集合List
- 獲取beanClass所有的Method屬性
- 獲取所有修飾Method屬性的注解,遍歷
- getMergedAttributes判斷Method是否被@Reference注解修飾,有則獲取注解的所有資訊;
- 找到set方法所對應的屬性;
- 加入結果集合List
private List<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> findAnnotatedMethodMetadata(final Class<?> beanClass) {
final List<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> elements = new LinkedList<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement>();
ReflectionUtils.doWithMethods(beanClass, method -> {
Method bridgedMethod = findBridgedMethod(method);
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
AnnotationAttributes attributes = getMergedAttributes(bridgedMethod, annotationType, getEnvironment(), true);
if (attributes != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) {
//....
// 找到set方法所對應的屬性
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass);
elements.add(new AnnotatedMethodElement(method, pd, attributes));
}
}
});
return elements;
}
獲取完之后, 退出, 回傳AnnotatedInjectionMetadata到(一)步驟中的呼叫處,然后會將這些Field和Method資訊放入快取;
postProcessPropertyValues
InstantiationAwareBeanPostProcessorAdapter抽象類已經定義好了該方法,子類AnnotationInjectedBeanPostProcessor 重寫該方法,進行@Reference的依賴注入程序;
public abstract class InstantiationAwareBeanPostProcessorAdapter implements SmartInstantiationAwareBeanPostProcessor {
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
}
}
public abstract class AnnotationInjectedBeanPostProcessor extends
InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered,
BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean {
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
// 尋找需要注入的屬性(被@Reference標注的Field)
InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}catch(Exception e){
//..例外處理
}
return pvs;
}
}
作業:
- 先獲取代表@Reference修飾的Field和Method資訊類;在(一)步驟中,已經掃描完成,放入快取,因此只需要先從快取中獲取;
- 執行屬性注入;
InjectionMetadata#inject(Object target, String beanName, PropertyValues pvs)
作用: 執行屬性注入
作業:
- 先獲取被@Reference修飾的屬性集合injectedElements;
- 遍歷集合injectedElements
- 執行屬性注入;
public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
Collection<InjectedElement> elementsToIterate =
(this.checkedElements != null ? this.checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
boolean debug = logger.isDebugEnabled();
for (InjectedElement element : elementsToIterate) {
if (debug) {
logger.debug("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
}
AnnotatedFieldElement#inject(target, beanName, pvs)
- InjectedElement 是 InjectionMetadata內部類,定義了inject方法, 但是代表被@Reference修飾的屬性的類是AnnotatedFieldElement
- 該類繼承了InjectedElement ,重寫了inject方法, 因此呼叫InjectedElement 其實就是呼叫AnnotatedFieldElement的inject方法
public class AnnotatedFieldElement extends InjectionMetadata.InjectedElement {}
inject作業:
- 獲取Field的型別;
- 獲取物件getInjectedObject
- 設定為可訪問
- 反射給Field設值;
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
// 給bean物件進行屬性賦值
Class<?> injectedType = field.getType();
// 獲取物件,然后進行注入
Object injectedObject = getInjectedObject(attributes, bean, beanName, injectedType, this);
ReflectionUtils.makeAccessible(field);
// 欄位賦值,injectedObject就是值
field.set(bean, injectedObject);
}
AnnotationInjectedBeanPostProcessor#getInjectedObject方法
獲取注入屬性實體;
作業:
- buildInjectedObjectCacheKey()生成注入物件的快取key;
- 從快取中獲取 屬性注入的實體;
- 如果存在, 直接回傳;
- 如果不能存在, 生成屬性注入的實體;
- 放入快取中;
protected Object getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
// ServiceBean:org.apache.dubbo.demo.DemoService#source=private org.apache.dubbo.demo.DemoService org.apache.dubbo.demo.consumer.comp.DemoServiceComponent.demoService#attributes={parameters=[Ljava.lang.String;@42e25b0b}
// 哪個Service應用了哪個型別的服務,通過什么方式引入的
String cacheKey = buildInjectedObjectCacheKey(attributes, bean, beanName, injectedType, injectedElement);
// cacheKey很雞肋,屬性名不一樣的時候,cacheKey不一樣,導致不能快取, 在一個Service中@Reference兩次同一個服務快取不到
Object injectedObject = injectedObjectsCache.get(cacheKey);
if (injectedObject == null) {
// 生成Bean
injectedObject = doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);
// Customized inject-object if necessary
injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
}
return injectedObject;
}
ReferenceAnnotationBeanPostProcessor#doGetInjectedBean
引數:
- attributes: 代表@Reference注解的所有配置的屬性資訊;
- bean : 代表執行屬性注入的類Bean實體;
- beanName: 代表執行屬性注入的類Bean實體的名稱;
- injectedType : 待注入的屬性型別;
作業:
- 獲取該屬性注入的服務Bean的名稱referencedBeanName ;
- 獲取referencedBeanName屬性;
- buildReferenceBeanIfAbsent生成一個ReferenceBean 物件;
- registerReferenceBean 注入到Spring容器中, 這樣就可以在其他地方就可以使用@Autowired注解自動注入;
- cacheInjectedReferenceBean-快取bean實體;
- getOrCreateProxy - 創建一個代理物件回傳;也就是意味著,最后注入的屬性是一個代理物件;
@Override
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
//該屬性注入的服務Bean的名稱referencedBeanName
String referencedBeanName = buildReferencedBeanName(attributes, injectedType);
/**
* The name of bean that is declared by {@link Reference @Reference} annotation injection
*/
// @Reference(methods=[Lorg.apache.dubbo.config.annotation.Method;@39b43d60) org.apache.dubbo.demo.DemoService
// 我要生成一個RefrenceBean,對應的beanName, 根據@Reference注解來標識不同
String referenceBeanName = getReferenceBeanName(attributes, injectedType);
// 生成一個ReferenceBean物件
ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referenceBeanName, attributes, injectedType);
// 把referenceBean添加到Spring容器中去
registerReferenceBean(referencedBeanName, referenceBean, attributes, injectedType);
//快取
cacheInjectedReferenceBean(referenceBean, injectedElement);
// 創建一個代理物件,Service中的屬性被注入的就是這個代理物件
// 內部會呼叫referenceBean.get();
return getOrCreateProxy(referencedBeanName, referenceBeanName, referenceBean, injectedType);
}
ReferenceAnnotationBeanPostProcessor#buildReferencedBeanName
創建一個ReferencedBeanName字串;
作業:
- 創建一個ServiceBeanNameBuilder構建者物件, 傳入@Reference注解資訊, 注入的服務型別,環境資訊;
- 生成ReferencedBeanName字串;
- 該名稱是以 注入服務介面類名 + 版本號 + 分組名稱 格式生成的;
- 如: ServiceBean:org.apache.dubbo.demo.DemoService 表示得到該服務Bean的beanName
private String buildReferencedBeanName(AnnotationAttributes attributes, Class<?> serviceInterfaceType) {
ServiceBeanNameBuilder serviceBeanNameBuilder = create(attributes, serviceInterfaceType, getEnvironment());
return serviceBeanNameBuilder.build();
}
// ServiceBeanNameBuilder # builder()
public String build() {
StringBuilder beanNameBuilder = new StringBuilder("ServiceBean");
// Required
append(beanNameBuilder, interfaceClassName);
// Optional
append(beanNameBuilder, version);
append(beanNameBuilder, group);
// Build and remove last ":"
String rawBeanName = beanNameBuilder.toString();
// Resolve placeholders
return environment.resolvePlaceholders(rawBeanName);
}
ReferenceAnnotationBeanPostProcessor#getReferenceBeanName
獲取ReferenceBeanName名稱字串;
作業:
- 獲取注解資訊中的id屬性;
- 判斷id是否為空,為空 ;generateReferenceBeanName生成一個ReferenceBeanName字串;
- 回傳
private String getReferenceBeanName(AnnotationAttributes attributes, Class<?> interfaceClass) {
// id attribute appears since 2.7.3
String beanName = getAttribute(attributes, "id");
// beanName為null時會進入if判斷
if (!hasText(beanName)) {
beanName = generateReferenceBeanName(attributes, interfaceClass);
}
return beanName;
}
generateReferenceBeanName生成一個ReferenceBeanName字串;
作業:
- 獲取@Reference注解資訊所有屬性項;
- 遍歷屬性項, 每個配置項以 “key = value ”的形式插入構造器字串;
- 插入屬性介面型別名稱;
- 回傳生成的ReferenceBeanName名稱;
private String generateReferenceBeanName(AnnotationAttributes attributes, Class<?> interfaceClass) {
StringBuilder beanNameBuilder = new StringBuilder("@Reference");
if (!attributes.isEmpty()) {
beanNameBuilder.append('(');
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
beanNameBuilder.append(entry.getKey())
.append('=')
.append(entry.getValue())
.append(',');
}
// replace the latest "," to be ")"
beanNameBuilder.setCharAt(beanNameBuilder.lastIndexOf(","), ')');
}
beanNameBuilder.append(" ").append(interfaceClass.getName());
return beanNameBuilder.toString();
}
referenceBeanName與referencedBeanName的區別
前者以 介面類路徑名 + 版本號 + 組名 創建的;
后者以 注解所有資訊 + 屬性介面型別 創建的;
buildReferenceBeanIfAbsent(referenceBeanName, attributes, injectedType)
目的: 創建一個ReferenceBean物件實體;
作業 :
- 根據生成的referenceBeanName從快取referenceBeanCache中獲取ReferenceBean實體;
- 存在, 直接回傳
- 不存在,呼叫ReferenceBeanBuilder#build()方法就創建一個ReferenceBean物件;
- 不存在, 創建完Reference實體后, 放入快取中;
- 回傳;
private ReferenceBean buildReferenceBeanIfAbsent(String referenceBeanName, AnnotationAttributes attributes, Class<?> referencedType) throws Exception {
ReferenceBean<?> referenceBean = referenceBeanCache.get(referenceBeanName);
if (referenceBean == null) {
// 生成了一個ReferenceBean物件,attributes是@Reference注解的引數值
ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder
.create(attributes, applicationContext)
.interfaceClass(referencedType);
referenceBean = beanBuilder.build();
referenceBeanCache.put(referenceBeanName, referenceBean);
} else if (!referencedType.isAssignableFrom(referenceBean.getInterfaceClass())) {
//...
}
return referenceBean;
}
ReferenceBeanBuilder#build()
創建一個Reference物件;
作業:
- 創建一個ReferenceBean物件
- 給ReferenceBean物件的屬性賦值
public final C build() throws Exception {
checkDependencies();
C configBean = doBuild();
configureBean(configBean);
//....
return configBean;
}
configureBean(C configBean)
作用: 設定ReferenceBean的屬性;
作業:
- @Reference注解中的配置項賦值給configBean
- 配置注冊中心;
- 配置監控中心;
- 配置Dubbo應用配置;
- 配置模塊資訊;
- 還是配置屬性資訊;
protected void configureBean(C configBean) throws Exception {
//
preConfigureBean(attributes, configBean);
configureRegistryConfigs(configBean);
configureMonitorConfig(configBean);
configureApplicationConfig(configBean);
configureModuleConfig(configBean);
// 設定applicationContext、interfaceName、consumer、methods屬性,并呼叫ReferenceBean物件的afterPropertiesSet方法
postConfigureBean(attributes, configBean);
}
//作業流程
//1.創建資料系結器, 這個是Spring的內容資料系結技術;
//2. 去空格;
//3. 決議并設定parameter引數;
//4. 使用資料系結技術, 將@Reference的基本資料設定給ReferenceBean;
@Override
protected void preConfigureBean(AnnotationAttributes attributes, ReferenceBean referenceBean) {
DataBinder dataBinder = new DataBinder(referenceBean);
// Register CustomEditors for special fields
// 去掉空格
dataBinder.registerCustomEditor(String.class, "filter", new StringTrimmerEditor(true));
dataBinder.registerCustomEditor(String.class, "listener", new StringTrimmerEditor(true));
// 你可以這么配@Reference(parameters = {"text=123"})
// 也可以這么配@Reference(parameters = {"text:123"})
// 最終都會轉變為Map設定到referenceBean中的parameters
dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws java.lang.IllegalArgumentException {
// Trim all whitespace
String content = StringUtils.trimAllWhitespace(text);
if (!StringUtils.hasText(content)) { // No content , ignore directly
return;
}
// replace "=" to ","
content = StringUtils.replace(content, "=", ",");
// replace ":" to ","
content = StringUtils.replace(content, ":", ",");
// String[] to Map
Map<String, String> parameters = CollectionUtils.toStringMap(commaDelimitedListToStringArray(content));
setValue(parameters);
}
});
dataBinder.bind(new AnnotationPropertyValuesAdapter(attributes, applicationContext.getEnvironment(), IGNORE_FIELD_NAMES));
}
//作業流程:
//1. 設定背景關系ApplicationContext;
//2. 設定介面;
//3. 設定ConsumerConfig配置; 對應的是 注解里面設定 的consumer 配置資訊;
//4. 設定Methodconfig配置
//4. 呼叫afterPropertiesSet(), 還是設定屬性星系;
@Override
protected void postConfigureBean(AnnotationAttributes attributes, ReferenceBean bean) throws Exception {
bean.setApplicationContext(applicationContext);
configureInterface(attributes, bean);
configureConsumerConfig(attributes, bean);
configureMethodConfig(attributes, bean);
bean.afterPropertiesSet();
}
public void afterPropertiesSet() throws Exception {
// 這個方法還是在給ReferenceBean物件的屬性賦值
if (applicationContext != null) {
BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConfigCenterBean.class, false, false);
}
// 如果@Reference注解中沒有配置consumer引數
if (getConsumer() == null) {
// 那么則從Spring容器中尋找ConsumerConfig型別的Bean, 比如通過@Bean定義了一個ConsumerConfig的Bean
Map<String, ConsumerConfig> consumerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConsumerConfig.class, false, false);
if (consumerConfigMap != null && consumerConfigMap.size() > 0) {
ConsumerConfig consumerConfig = null;
// 可能存在多個ConsumerConfig型別的Bean,遍歷這些Bean,取第一個沒有配置default或者default為true的Bean作為consumer的值
for (ConsumerConfig config : consumerConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (consumerConfig != null) {
throw new IllegalStateException("Duplicate consumer configs: " + consumerConfig + " and " + config);
}
consumerConfig = config;
}
}
if (consumerConfig != null) {
setConsumer(consumerConfig);
}
}
}
if (getApplication() == null
&& (getConsumer() == null || getConsumer().getApplication() == null)) {
Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false);
if (applicationConfigMap != null && applicationConfigMap.size() > 0) {
ApplicationConfig applicationConfig = null;
for (ApplicationConfig config : applicationConfigMap.values()) {
if (applicationConfig != null) {
throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
}
applicationConfig = config;
}
if (applicationConfig != null) {
setApplication(applicationConfig);
}
}
}
if (getModule() == null
&& (getConsumer() == null || getConsumer().getModule() == null)) {
Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false);
if (moduleConfigMap != null && moduleConfigMap.size() > 0) {
ModuleConfig moduleConfig = null;
for (ModuleConfig config : moduleConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (moduleConfig != null) {
throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
}
moduleConfig = config;
}
}
if (moduleConfig != null) {
setModule(moduleConfig);
}
}
}
// 如果@Reference注解上沒有配置registryIds
// 那么則看application或consumer上有沒有配置registryIds
if (StringUtils.isEmpty(getRegistryIds())) {
if (getApplication() != null && StringUtils.isNotEmpty(getApplication().getRegistryIds())) {
setRegistryIds(getApplication().getRegistryIds());
}
if (getConsumer() != null && StringUtils.isNotEmpty(getConsumer().getRegistryIds())) {
setRegistryIds(getConsumer().getRegistryIds());
}
}
if (CollectionUtils.isEmpty(getRegistries())
&& (getConsumer() == null || CollectionUtils.isEmpty(getConsumer().getRegistries()))
&& (getApplication() == null || CollectionUtils.isEmpty(getApplication().getRegistries()))) {
Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false);
if (registryConfigMap != null && registryConfigMap.size() > 0) {
List<RegistryConfig> registryConfigs = new ArrayList<>();
if (StringUtils.isNotEmpty(registryIds)) {
Arrays.stream(COMMA_SPLIT_PATTERN.split(registryIds)).forEach(id -> {
if (registryConfigMap.containsKey(id)) {
registryConfigs.add(registryConfigMap.get(id));
}
});
}
if (registryConfigs.isEmpty()) {
for (RegistryConfig config : registryConfigMap.values()) {
if (StringUtils.isEmpty(registryIds)) {
registryConfigs.add(config);
}
}
}
if (!registryConfigs.isEmpty()) {
super.setRegistries(registryConfigs);
}
}
}
if (getMetadataReportConfig() == null) {
Map<String, MetadataReportConfig> metadataReportConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MetadataReportConfig.class, false, false);
if (metadataReportConfigMap != null && metadataReportConfigMap.size() == 1) {
// first elements
super.setMetadataReportConfig(metadataReportConfigMap.values().iterator().next());
} else if (metadataReportConfigMap != null && metadataReportConfigMap.size() > 1) {
throw new IllegalStateException("Multiple MetadataReport configs: " + metadataReportConfigMap);
}
}
// 如果@Reference注解中沒有配置configCenter屬性
// 那么則從Spring容器中找ConfigCenterConfig型別的bean
if (getConfigCenter() == null) {
Map<String, ConfigCenterConfig> configenterMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConfigCenterConfig.class, false, false);
// 只能配一個ConfigCenterConfig
if (configenterMap != null && configenterMap.size() == 1) {
// 設定進去
super.setConfigCenter(configenterMap.values().iterator().next());
} else if (configenterMap != null && configenterMap.size() > 1) {
throw new IllegalStateException("Multiple ConfigCenter found:" + configenterMap);
}
}
if (getMonitor() == null
&& (getConsumer() == null || getConsumer().getMonitor() == null)
&& (getApplication() == null || getApplication().getMonitor() == null)) {
Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false);
if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
MonitorConfig monitorConfig = null;
for (MonitorConfig config : monitorConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (monitorConfig != null) {
throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
}
monitorConfig = config;
}
}
if (monitorConfig != null) {
setMonitor(monitorConfig);
}
}
}
if (getMetrics() == null) {
Map<String, MetricsConfig> metricsConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MetricsConfig.class, false, false);
if (metricsConfigMap != null && metricsConfigMap.size() > 0) {
MetricsConfig metricsConfig = null;
for (MetricsConfig config : metricsConfigMap.values()) {
if (metricsConfig != null) {
throw new IllegalStateException("Duplicate metrics configs: " + metricsConfig + " and " + config);
}
metricsConfig = config;
}
if (metricsConfig != null) {
setMetrics(metricsConfig);
}
}
}
if (shouldInit()) {
getObject();
}
}
registerReferenceBean(referencedBeanName, referenceBean, attributes, injectedType)
目的:將ReferenceBean注入容器, 這個步驟中,會將服務實作類注入容器,這樣一個地方使用@Reference注解后,其他地方就可以通過@Autowired自動注入了,
作業:
- 獲取Bean工廠;
- 獲取referenceBeanName字串, 將@Reference注解內容以鍵值對拼接 + 服務介面名; (應該是重復操作了)
- 判斷容器是否已經存在這個Bean了,如果存在,則是本地服務(@Service注解修飾的服務在@Reference注解之前決議完成了)
-
存在的話,則根據referenceBeanName去BeanFactory中獲取 代表@Service注解的ServiceBean的BeanDefinition;
-
獲取ServiceBean的ref屬性;
-
獲取ServiceBean的名稱;
-
注冊別名,如果別名和ServiceBean的別名一樣,就不需要注冊別名, 不一樣就以ServiceBean的Bean名稱為鍵, referenceBeanName為值,放入別名緩沖中;
-
不存在的話,就往容器中注入生成的referenceBean;
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
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanFactory.getBeanDefinition(referencedBeanName);
RuntimeBeanReference runtimeBeanReference = (RuntimeBeanReference) beanDefinition.getPropertyValues().get("ref"); // ServiceBean --- ref
String serviceBeanName = runtimeBeanReference.getBeanName();
beanFactory.registerAlias(serviceBeanName, beanName);
} else { // Remote @Service Bean
if (!beanFactory.containsBean(beanName)) {
beanFactory.registerSingleton(beanName, referenceBean);
}
}
}
cacheInjectedReferenceBean(referenceBean, injectedElement)
目的: 將生成的referenceBean實體,放入快取;
- 如果是屬性注入, 則放入injectedFieldReferenceBeanCache中;
- 如果是方法注入, 則放入injectedMethodReferenceBeanCache中;
private void cacheInjectedReferenceBean(ReferenceBean referenceBean,
InjectionMetadata.InjectedElement injectedElement) {
if (injectedElement.getMember() instanceof Field) {
injectedFieldReferenceBeanCache.put(injectedElement, referenceBean);
} else if (injectedElement.getMember() instanceof Method) {
injectedMethodReferenceBeanCache.put(injectedElement, referenceBean);
}
}
getOrCreateProxy(referencedBeanName, referenceBeanName, referenceBean, injectedType)
目的: 創建一個代理物件回傳;
為什么是代理物件,而不是上面容器中的服務實作類;
個人看法:
不同服務,分布在不同的機器上,如果是本地服務還好, 如果是遠程服務, 在呼叫服務還需要額外操作,
例如負載均衡, 注冊中心等功能;因此,不能直接回傳服務實作類,而是回傳代理物件, 公共的操作讓代理物件去執行;
作業:
- 判斷ServiceBean是否存在,存在則是本地服務, 不存在則是遠程服務;
- 本地服務:會生成一個代理物件,代理物件的InvocationHandler會放入快取中, 回傳代理物件;
- 遠程服務:呼叫get()獲取一個代理物件回傳;
private Object getOrCreateProxy(String referencedBeanName, String referenceBeanName, ReferenceBean referenceBean, Class<?> serviceInterfaceType) {
if (existsServiceBean(referencedBeanName)) { // If the local @Service Bean exists, build a proxy of ReferenceBean
return newProxyInstance(getClassLoader(), new Class[]{serviceInterfaceType},
wrapInvocationHandler(referenceBeanName, referenceBean));
} else { // ReferenceBean should be initialized and get immediately
// 重點
return referenceBean.get();
}
}
private InvocationHandler wrapInvocationHandler(String referenceBeanName, ReferenceBean referenceBean) {
return localReferenceBeanInvocationHandlerCache.computeIfAbsent(referenceBeanName, name ->
new ReferenceBeanInvocationHandler(referenceBean));
}
總結
@Reference注解服務引入的程序:
有了這些邏輯,@Reference注解服務引入的程序是這樣的:
- 得到當前所引入服務對應的ServiceBean的beanName(原始碼中叫referencedBeanName)
- 根據@Reference注解的所有資訊+屬性介面型別得到一個referenceBeanName
- 根據referenceBeanName從referenceBeanCache獲取對應的ReferenceBean,如果沒有則創建一個ReferenceBean
- 根據referencedBeanName(ServiceBean的beanName)判斷Spring容器中是否存在該bean,如果存在則給ref屬性所對應的bean取一個別名,別名為referenceBeanName,
a. 如果Spring容器中不存在referencedBeanName對應的bean,則判斷容器中是否存在referenceBeanName所對應的Bean,如果不存在則將創建出來的ReferenceBean注冊到Spring容器中(此處這么做就支持了可以通過@Autowired注解也可以使用服務了,ReferenceBean是一個FactoryBean) - 如果referencedBeanName存在對應的Bean,則額外生成一個代理物件,代理物件的InvocationHandler會快取在localReferenceBeanInvocationHandlerCache中,這樣如果引入的是同一個服務,并且這個服務在本地,
- 如果referencedBeanName不存在對應的Bean,則直接呼叫ReferenceBean的get()方法得到一個代理物件
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/439242.html
標籤:其他
