学习目标
- 本文主要讲解Dubbo基于注解的方式集成spring
第2章 注解方式整合
注解方式已经是现在的主流了,例如springboot现在都是零xml配置了,只要通过少量的配置就可以完成框架的引用。
2.1 案例
生产者
配置类
@Configuration
//作用 扫描 @DubboService注解 @DubboReference
@EnableDubbo(scanBasePackages = "com.example")
@PropertySource("classpath:/dubbo-provider.properties")
public class ProviderConfiguration {
}
dubbo-provider.properties配置
dubbo.application.name=dubbo_provider
dubbo.registry.address=zookeeper://${zookeeper.address:127.0.0.1}:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.config-center.address=zookeeper://${zookeeper.address:127.0.0.1}:2181
服务暴露
@DubboService
public class UserServiceImpl implements UserService {
@Override
public String queryUser(String s) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(s);
System.out.println("==========provider===========" + s);
return "OK--" + s;
}
@Override
public void doKill(String s) {
System.out.println("==========provider===========" + s);
}
}
启动
public class AnnotationProvider {
public static void main(String[] args) throws InterruptedException {
ZKTools.generateDubboProperties();
new AnnotationConfigApplicationContext(ProviderConfiguration.class);
System.out.println("dubbo service started.");
new CountDownLatch(1).await();
}
}
2.2 优势
可以看到,只需要在需要暴露的服务上面加上一个@DubboService注解就可以完成服务的暴露了,配置量非常少,但是这种方式也有一定的侵入性。
2.3 源码分析
2.3.1 @EnableDubbo
@EnableDubbo注解可以理解为引入dubbo功能,其实在这里它起到的作用就是两个,
1、扫描类上面的@DubboService注解
2、扫描类中属性或者方法上面的@DubboReference注解
那为什么@EnableDubbo会被spring扫描到呢?
要回答这个问题,首先我们得看看@EnableDubbo的结构。
可以看到,在@DubboComponentScan注解中有一个@Import注解,实际上spring能扫描到的就是这个@Import注解,通过扫描到@Import注解从而把import进来的类变成BeanDefinition交给spring实例化。
具体spring如何扫描的,请看下面步骤:
1、通过spring上下文对象的实例化把ConfigurationClassPostProcessor变成BeanDefinition
2、ConfigurationClassPostProcessor对@Import的扫描
由于ConfigurationClassPostProcessor类是一个BeanDefinitionRegistryPostProcessor类型的,所以在spring容器中它会优先被实例化,实例化的地方在refresh核心方法的:
所以当ConfigurationClassPostProcessor实例化的时候就调用到postProcessBeanDefinitionRegistry方法,方法逻辑如下:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against" + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " +registry);
}
this.registriesPostProcessed.add(registryId);
//核心逻辑,重点看,重要程度5
processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
//获取所有的beanNames
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//如果有该标识就不再处理
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//判断是否是候选的需要处理的BeanDefinition,如果是则放入容器configCandidates
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
//如果容器为空,则直接返回
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
//对需要处理的所有beanDefinition排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
//候选BeanDefinition的解析器
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//解析核心流程,重点看,重要程度5
//其实就是把类上面的特殊注解解析出来最终封装成beanDefinition
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>
(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//@Bean @Import 内部类 @ImportedResource ImportBeanDefinitionRegistrar具体处理逻辑
this.reader.loadBeanDefinitions(configClasses);
//已经解析完成了的类
alreadyParsed.addAll(configClasses);
candidates.clear();
//比较差异又走一遍解析流程
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd,
this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
就是在上面方面里面的this.reader.loadBeanDefinitions(configClasses);这行代码对所有BeanDefinition中对应类上如果有@Import注解进行了解析处理,这样spring就能够扫描的@EnableDubbo注解了。
2.3.2 DubboComponentScanRegistrar
DubboComponentScanRegistrar类是通过@EnableDubbo上面的@DubboComponentScan注解import进来的,它是一个ImportBeanDefinitionRegistrar类型的,所有当被引入进来以后就会被spring调用到它的registerBeanDefinitions方法,代码如下:
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {
// @since 2.7.6 Register the common beans
registerCommonBeans(registry);
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
registerServiceAnnotationPostProcessor(packagesToScan, registry);
}
至于为什么spring能调到这个方法,起调用逻辑还是在this.reader.loadBeanDefinitions(configClasses);这行代码里面,具体调用代码:
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar,AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) -> registrar.registerBeanDefinitions(metadata, this.registry,
this.importBeanNameGenerator));
}
我们在来看看registerBeanDefinitions方法做了些什么, registerCommonBeans(registry);方法前面我们分析过,注册了两个比较重要的类
1、ReferenceAnnotationBeanPostProcessor
2、DubboBootstrapApplicationListener
registerServiceAnnotationPostProcessor(packagesToScan, registry);这行代码里面又注册了一个比较重要的类,ServiceAnnotationPostProcessor
所以该方法其实核心就是注册了三个比较重要的类给了spring容器:
1、ReferenceAnnotationBeanPostProcessor
2、DubboBootstrapApplicationListener
3、ServiceAnnotationPostProcessor
DubboBootstrapApplicationListener这个类前面我们分析过,它就是在spring容器启动完成后通过spring发布一个spring容器启动完成的事件,然后该类捕获到事件,通过捕获事件来完成服务的发布和引用的,这里就不再赘述了。现在主要分析ServiceAnnotationPostProcessor和ReferenceAnnotationBeanPostProcessor
2.3.3 ServiceAnnotationPostProcessor
首先这个ServiceAnnotationPostProcessor类是干什么的呢?
这个类的作用就是用来扫描类上面的@DubboService注解的,就只有这个功能。
该类的类型是BeanDefinitionRegistryPostProcessor类型的。所以它会被spring调用到postProcessBeanDefinitionRegistry方法,调用逻辑如下:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws
BeansException {
this.registry = registry;
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
//这里是扫描的核心逻辑
scanServiceBeans(resolvedPackagesToScan, registry);
} else {
if (logger.isWarnEnabled()) {
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
}
}
}
private void scanServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
//定义一个扫描器,这个dubbo扫描器其实就是继承了spring的ClassPathBeanDefinitionScanner扫描器
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
//对扫描器添加需要扫描的注解类型,这里的注解类型有三种,阿帕奇的@Service,@DubboService,阿里巴巴的@Service
for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {
scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
}
ScanExcludeFilter scanExcludeFilter = new ScanExcludeFilter();
scanner.addExcludeFilter(scanExcludeFilter);
for (String packageToScan : packagesToScan) {
// avoid duplicated scans
if (servicePackagesHolder.isPackageScanned(packageToScan)) {
if (logger.isInfoEnabled()) {
logger.info("Ignore package who has already bean scanned: " + packageToScan);
}
continue;
}
//这里就是核心的扫描代码
//扫描的核心流程,其实就是递归找文件的过程,如果找的是文件夹则递归找,如果是文件则根据完整限定名反射出反射对象,根据反射对象判断类上是否有DubboService注解,如果又则把该类变成BeanDefinition
// Registers @Service Bean first
scanner.scan(packageToScan);
// Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not.
Set<BeanDefinitionHolder> beanDefinitionHolders =
//这行代码就是根据前面的扫描找到的BeanDefinition集合,获取这个集合
findServiceBeanDefinitionHolders(scanner, packageToScan, registry,beanNameGenerator);
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
if (logger.isInfoEnabled()) {
List<String> serviceClasses = new ArrayList<>(beanDefinitionHolders.size());
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
serviceClasses.add(beanDefinitionHolder.getBeanDefinition().getBeanClassName());
}
logger.info("Found " + beanDefinitionHolders.size() + " classes annotated by Dubbo @Service under package [" + packageToScan + "]: " + serviceClasses);
}
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
//这行代码很重要,因为要完成服务暴露那么就必须调用到ServiceBean中的export方法
//这行代码就是根据有注解的类的BeanDefinition来创建根该类对应的ServiceBean的BeanDefinition对象
processScannedBeanDefinition(beanDefinitionHolder, registry, scanner);
servicePackagesHolder.addScannedClass(beanDefinitionHolder.getBeanDefinition().getBeanClassName());
}
} else {
if (logger.isWarnEnabled()) {
logger.warn("No class annotated by Dubbo @Service was found under package [" + packageToScan + "], ignore re-scanned classes: " + scanExcludeFilter.getExcludedCount());
}
}
servicePackagesHolder.addScannedPackage(packageToScan);
}
}
private void processScannedBeanDefinition(BeanDefinitionHolder beanDefinitionHolder,
BeanDefinitionRegistry registry,
DubboClassPathBeanDefinitionScanner scanner) {
Class<?> beanClass = resolveClass(beanDefinitionHolder);
Annotation service = findServiceAnnotation(beanClass);
// The attributes of @Service annotation
Map<String, Object> serviceAnnotationAttributes = AnnotationUtils.getAttributes(service,
true);
String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
// ServiceBean Bean name
String beanName = generateServiceBeanName(serviceAnnotationAttributes,
serviceInterface);
AbstractBeanDefinition serviceBeanDefinition =
//这里就是创建ServiceBean的BeanDefinition
buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface,
annotatedServiceBeanName);
registerServiceBeanDefinition(beanName, serviceBeanDefinition, serviceInterface);
}
OK,从上面的分析,我们知道,扫描到有@DubboService注解的类以后,实际上会创建跟该类对应的ServiceBean的实例,也就是有一个@DubboService注解的类就会对应一个ServiceBean的实例在spring容器中。那么又回到了上面xml分析的流程了,ServiceBean实例化走到afterPropertiesSet方法,然后spring容器启动完成走到dubbo的监听器完成服务发布了。
2.3.4 ReferenceAnnotationBeanPostProcessor
ReferenceAnnotationBeanPostProcessor的作用就是完成@DubboReference属性或者方法的依赖注入,其依赖注入的流程也是完全依赖spring的,所以我们必须要掌握spring的依赖注入流程,其实spring的依赖注入核心就两点;
2.3.4.1 spring的依赖注入
1、注解的收集
2、实例的注入
以@Autowired注解的属性来分析spring的依赖注入,例如:
@Component
public class SpringTest {
@Autowired
private UserService userService;
private UserService userService1;
private UserService userService2;
private UserService userService3;
private UserService userService4;
public UserService getUserService() {
return userService;
}
@PostConstruct
public void init() {
System.out.println(userService);
}
}
1、@Autowired注解收集
注解收集的核心流程
refresh--->finishBeanFactoryInitialization--->preInstantiateSingletons--->beanFactory.getBean--->AbstractBeanFactory.doGetBean--->createBean--->doCreateBean--->applyMergedBeanDefinitionPostProcessors
对应的接口类型MergedBeanDefinitionPostProcessor,这个类型的BeanPostProcessor的埋点就是用来处理注解收集这个功能点的,只有关系该功能点的类才会对该接口的方法进行实现,其他不关心的可以不管MergedBeanDefinitionPostProcessor该接口的方法实现,也就是方法可以直接是一个空方法。
AutowiredAnnotationBeanPostProceessor类就是用来对@Autowired注解进行支持的。该类的注册是在spring上下文对象的构造函数的完成注册的。
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//注解收集核心逻辑
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable 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.
//先从缓存拿结果
InjectionMetadata 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);
}
//主要看这个方法
//收集的核心逻辑
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
//其实这里就是拿到类上所有的field,然后判断field上是否有@Autowired注解,如果有则封装成对象
//寻找field上面的@Autowired注解并封装成对象
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
注解的收集就完成了
2、@Autowired的依赖注入
依赖注入的核心方法:
//ioc di,依赖注入的核心方法,该方法必须看,重要程度:5
populateBean(beanName, mbd, instanceWrapper);
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
//这里很有意思,写接口可以让所有类都不能依赖注入
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE)
{
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() !=
AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
//重点看这个if代码块,重要程度 5
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//依赖注入过程,@Autowired的支持。。这里完成了依赖注入
PropertyValues pvsToUse = ibp.postProcessProperties(pvs,bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw,mbd.allowCaching);
}
//老版本用这个完成依赖注入过程,@Autowired的支持
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds,bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
//这个方法很鸡肋了,建议不看,是老版本用<property name="username" value="Jack"/>
//标签做依赖注入的代码实现,复杂且无用
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
这里又会调用到AutowiredAnnotationBeanPostProceessor类的方法进行依赖注入。
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
通过前面的收集结果,我们知道了哪些属性获取方法有注解,那么在这里我们只要根据有注解的属性进行依赖注入就可以了,这里就不再赘述了。
2.3.4.2 dubbo的依赖注入
其实dubbo的依赖注入流程跟spring是一模一样的,也是借助BeanPostProcessor类型的接口来实现,只是这个类是ReferenceAnnotationBeanPostProcessor
OK,我们来一个示例:
public class Ioc {
@DubboReference
private UserService userService;
@PostConstruct
public void init() {
System.out.println(userService);
}
}
也是两个步骤,只是这两个步骤是由ReferenceAnnotationBeanPostProcessor它来完成的。
1、@DubboReference注解收集
2、实例的依赖注入
1、@DubboReference注解收集
收集的逻辑跟spring是一模一样的,如图:
会走到ReferenceAnnotationBeanPostProcessor类中进行注解收集;
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType != null) {
if (isReferenceBean(beanDefinition)) {
//mark property value as optional
List<PropertyValue> propertyValues = beanDefinition.getPropertyValues().getPropertyValueList();
for (PropertyValue propertyValue : propertyValues) {
propertyValue.setOptional(true);
}
} else if (isAnnotatedReferenceBean(beanDefinition)) {
// extract beanClass from java-config bean method generic return type:
ReferenceBean<DemoService>
//Class beanClass = getBeanFactory().getType(beanName);
} else {
//收集有@DubboReference注解的属性或者方法并封装成对象
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType,null);
metadata.checkConfigMembers(beanDefinition);
try {
//这里是对每一个有@DubboReference注解的属性或者方法创建一个ReferenceBean的BeanDefinition对象,因为要完成服务的引用,必须要有@ReferenceBean的实例
prepareInjection(metadata);
} catch (Exception e) {
throw new IllegalStateException("Prepare dubbo reference injection element failed", e);
}
}
}
}
prepareInjection(metadata);的核心代码贴一下:
RootBeanDefinition beanDefinition = new RootBeanDefinition();
//这里就会创建ReferenceBean对象
beanDefinition.setBeanClassName(ReferenceBean.class.getName());
beanDefinition.getPropertyValues().add(ReferenceAttributes.ID, referenceBeanName);
// set attribute instead of property values
beanDefinition.setAttribute(Constants.REFERENCE_PROPS, attributes);
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, interfaceName);
// create decorated definition for reference bean, Avoid being instantiated when getting the beanType of ReferenceBean
// see org.springframework.beans.factory.support.AbstractBeanFactory#getTypeForFactoryBean()
GenericBeanDefinition targetDefinition = new GenericBeanDefinition();
targetDefinition.setBeanClass(interfaceClass);
String id = (String) beanDefinition.getPropertyValues().get(ReferenceAttributes.ID);
beanDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition,id+"_decorated"));
// signal object type since Spring 5.2
beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);
beanDefinitionRegistry.registerBeanDefinition(referenceBeanName, beanDefinition);
总结一下,收集注解会收集@DubboReference注解的属性或方法,然后还会创建跟@DubboReference对应的ReferenceBean对象,因为要完成代理的生成和服务的引用。
2、实例的依赖注入
@DubboReference属性的依赖注入,流程跟spring也是一样的,处理类是ReferenceAnnotationBeanPostProcessor
会走到ReferenceAnnotationBeanPostProcessor类中的postProcessPropertyValues方法完成属性依赖注入
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
try {
//这里走缓存拿手机的结果
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName,bean.getClass(), pvs);
//再次确定有没有生成Referencebean的BeanDefinition
prepareInjection(metadata);
//依赖注入
metadata.inject(bean, beanName, pvs);
} catch (BeansException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName() + " dependencies is failed",ex);
}
return pvs;
}
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
//获取代理对象的核心方法
Object injectedObject = getInjectedObject(attributes, bean, beanName, getInjectedType(),this);
//属性的方式注入
if (member instanceof Field) {
Field field = (Field) member;
ReflectionUtils.makeAccessible(field);
field.set(bean, injectedObject);
} else if (member instanceof Method) {
Method method = (Method) member;
ReflectionUtils.makeAccessible(method);
method.invoke(bean, injectedObject);
}
}
protected Object getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,AnnotatedInjectElement injectedElement) throws
Exception {
// String cacheKey = buildInjectedObjectCacheKey(attributes, bean, beanName,injectedType, injectedElement);
//
// Object injectedObject = injectedObjectsCache.get(cacheKey);
//
// if (injectedObject == null) {
// injectedObject = doGetInjectedBean(attributes, bean, beanName, injectedType,injectedElement);
// // Customized inject-object if necessary
// injectedObjectsCache.put(cacheKey, injectedObject);
// }
// return injectedObject;
return doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);
}
@Override
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,AnnotatedInjectElement injectedElement) throws Exception
{
if (injectedElement.injectedObject == null) {
throw new IllegalStateException("The AnnotatedInjectElement of @DubboReference should be inited before injection");
}
//getBean获取实例,id是 UserService
return getBeanFactory().getBean((String) injectedElement.injectedObject);
}
前面创建了ReferenceBean对象,其中有一个ReferenceBean对象的id就是userService.所有这里getBean会获取到ReferenceBean的实例或者其FactoryBean的getObject返回的实例,其实ReferenceBean是有实现FactoryBean接口的,所有这里会返回getObject返回的实例,我们看看ReferenceBean。
public class ReferenceBean<T> implements FactoryBean<T>,ApplicationContextAware, BeanClassLoaderAware, BeanNameAware, InitializingBean,DisposableBean
@Override
public T getObject() {
if (lazyProxy == null) {
createLazyProxy();
}
return (T) lazyProxy;
}
private void createLazyProxy() {
//set proxy interfaces
//see also:org.apache.dubbo.rpc.proxy.AbstractProxyFactory.getProxy(org.apache.dubbo.rpc.Invoker<T>,boolean)
//很明显这里会用spring的代理工厂生成代理对象
ProxyFactory proxyFactory = new ProxyFactory();
//定义哦了TargetSource类型实例,spring中会有该类调用其getTarget方法拿到目标对象,其实这里就会生成Dubbo的代理
proxyFactory.setTargetSource(new DubboReferenceLazyInitTargetSource());
proxyFactory.addInterface(interfaceClass);
Class<?>[] internalInterfaces = AbstractProxyFactory.getInternalInterfaces();
for (Class<?> anInterface : internalInterfaces) {
proxyFactory.addInterface(anInterface);
}
if (!StringUtils.isEquals(interfaceClass.getName(), interfaceName)) {
//add service interface
try {
Class<?> serviceInterface = ClassUtils.forName(interfaceName, beanClassLoader);
proxyFactory.addInterface(serviceInterface);
} catch (ClassNotFoundException e) {
// generic call maybe without service interface class locally
}
}
//返回spring的代理
this.lazyProxy = proxyFactory.getProxy(this.beanClassLoader);
}
private class DubboReferenceLazyInitTargetSource extends AbstractLazyCreationTargetSource {
@Override
protected Object createObject() throws Exception {
return getCallProxy();
}
@Override
public synchronized Class<?> getTargetClass() {
return getInterfaceClass();
}
}
//父类的getTarget方法会被spring的advice调用到,又会回调子类的createObject方法,模板设计模式
@Override
public synchronized Object getTarget() throws Exception {
if (this.lazyTarget == null) {
logger.debug("Initializing lazy target object");
this.lazyTarget = createObject();
}
return this.lazyTarget;
}
private Object getCallProxy() throws Exception {
if (referenceConfig == null) {
throw new IllegalStateException("ReferenceBean is not ready yet, please make sure to call reference interface method after dubbo is started.");
}
//get reference proxy
return referenceConfig.get();
}
所以从这个流程看,@DubboReference依赖注入的对象其实就一个spring的代理对象,然后用这个代理对象调用的时候,最终会调到TargetSource对象的getTarget方法,由这个方法会调到referenceConfig.get()方法生成dubbo的代理对象,referenceConfig.get()这个方法也是引用dubbo服务的核心方法。
下文预告
- Dubbo的SPI机制了解
- 理解Dubbo的SPI机制与jdk或者spring的SPI机制的区别
本文暂时没有评论,来添加一个吧(●'◡'●)