/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.dubbo.config.spring.beans.factory.annotation; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.config.annotation.Service; import com.alibaba.dubbo.config.spring.ServiceBean; import com.alibaba.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner; import org.springframework.beans.BeansException; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.config.SingletonBeanRegistry; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.ManagedList; import org.springframework.context.EnvironmentAware; import org.springframework.context.ResourceLoaderAware; import org.springframework.context.annotation.AnnotationBeanNameGenerator; import org.springframework.context.annotation.AnnotationConfigUtils; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; import org.springframework.context.annotation.ConfigurationClassPostProcessor; import org.springframework.core.env.Environment; import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import static com.alibaba.spring.util.ObjectUtils.of; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; import static org.springframework.context.annotation.AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR; import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; import static org.springframework.util.ClassUtils.resolveClassName; /** * {@link Service} Annotation * {@link BeanDefinitionRegistryPostProcessor Bean Definition Registry Post Processor} * * @since 2.5.8 */ public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware, BeanClassLoaderAware { private final Logger logger = LoggerFactory.getLogger(getClass()); private final Set<String> packagesToScan; private Environment environment; private ResourceLoader resourceLoader; private ClassLoader classLoader; public ServiceAnnotationBeanPostProcessor(String... packagesToScan) { this(Arrays.asList(packagesToScan)); } public ServiceAnnotationBeanPostProcessor(Collection<String> packagesToScan) { this(new LinkedHashSet<String>(packagesToScan)); } public ServiceAnnotationBeanPostProcessor(Set<String> packagesToScan) { this.packagesToScan = packagesToScan; } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { // 解析指定扫描的包名=》 Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan); if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) { // 注册服务提供者bean定义=》 registerServiceBeans(resolvedPackagesToScan, registry); } else { if (logger.isWarnEnabled()) { logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!"); } } } /** * Registers Beans whose classes was annotated {@link Service} 注册类为带注释服务的bean * * @param packagesToScan The base packages to scan * @param registry {@link BeanDefinitionRegistry} */ private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) { // 创建dubbo服务类bean定义扫描器 DubboClassPathBeanDefinitionScanner scanner = new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader); // 解析beanName解析器=》 BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry); scanner.setBeanNameGenerator(beanNameGenerator); // 扫描直接@Service scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class)); for (String packageToScan : packagesToScan) { // Registers @Service Bean first 扫描@Service注解的bean=》 scanner.scan(packageToScan); // Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not. 查找@ComponentScan指定的包路径下带有@Service的bean的bean定义=》 Set<BeanDefinitionHolder> beanDefinitionHolders = findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator); if (!CollectionUtils.isEmpty(beanDefinitionHolders)) { for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) { // 注册service bean=》 registerServiceBean(beanDefinitionHolder, registry, scanner); } if (logger.isInfoEnabled()) { logger.info(beanDefinitionHolders.size() + " annotated Dubbo's @Service Components { " + beanDefinitionHolders + " } were scanned under package[" + packageToScan + "]"); } } else { if (logger.isWarnEnabled()) { logger.warn("No Spring Bean annotating Dubbo's @Service was found under package[" + packageToScan + "]"); } } } } /** * It'd better to use BeanNameGenerator instance that should reference * {@link ConfigurationClassPostProcessor#componentScanBeanNameGenerator}, * thus it maybe a potential problem on bean name generation. * * @param registry {@link BeanDefinitionRegistry} * @return {@link BeanNameGenerator} instance * @see SingletonBeanRegistry * @see AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR * @see ConfigurationClassPostProcessor#processConfigBeanDefinitions * @since 2.5.8 * 最好使用应该引用ConfigurationClassPostProcessor.componentScanBeanNameGenerator的BeanNameGenerator实例,这样在生成bean名时可能会出现问题。 */ private BeanNameGenerator resolveBeanNameGenerator(BeanDefinitionRegistry registry) { BeanNameGenerator beanNameGenerator = null; if (registry instanceof SingletonBeanRegistry) { SingletonBeanRegistry singletonBeanRegistry = SingletonBeanRegistry.class.cast(registry); beanNameGenerator = (BeanNameGenerator) singletonBeanRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR); } if (beanNameGenerator == null) { if (logger.isInfoEnabled()) { logger.info("BeanNameGenerator bean can't be found in BeanFactory with name [" + CONFIGURATION_BEAN_NAME_GENERATOR + "]"); logger.info("BeanNameGenerator will be a instance of " + AnnotationBeanNameGenerator.class.getName() + " , it maybe a potential problem on bean name generation."); } beanNameGenerator = new AnnotationBeanNameGenerator(); } return beanNameGenerator; } /** * Finds a {@link Set} of {@link BeanDefinitionHolder BeanDefinitionHolders} whose bean type annotated * {@link Service} Annotation.找到一组beandefinitionholder,其bean类型注释了服务注释。 * * @param scanner {@link ClassPathBeanDefinitionScanner} * @param packageToScan pachage to scan * @param registry {@link BeanDefinitionRegistry} * @return non-null * @since 2.5.8 */ private Set<BeanDefinitionHolder> findServiceBeanDefinitionHolders( ClassPathBeanDefinitionScanner scanner, String packageToScan, BeanDefinitionRegistry registry, BeanNameGenerator beanNameGenerator) { Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(packageToScan); Set<BeanDefinitionHolder> beanDefinitionHolders = new LinkedHashSet<BeanDefinitionHolder>(beanDefinitions.size()); for (BeanDefinition beanDefinition : beanDefinitions) { String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry); BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, beanName); beanDefinitionHolders.add(beanDefinitionHolder); } return beanDefinitionHolders; } /** * Registers {@link ServiceBean} from new annotated {@link Service} {@link BeanDefinition} 从新的带注释的服务bean定义注册ServiceBean * * @param beanDefinitionHolder * @param registry * @param scanner * @see ServiceBean * @see BeanDefinition */ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry, DubboClassPathBeanDefinitionScanner scanner) { Class<?> beanClass = resolveClass(beanDefinitionHolder); // 从beanClass上获取@service注解对象 Service service = findAnnotation(beanClass, Service.class); // 解析@service注解指定的interface的Class对象 Class<?> interfaceClass = resolveServiceInterfaceClass(beanClass, service); String annotatedServiceBeanName = beanDefinitionHolder.getBeanName(); // 构建service bean定义=》 AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(service, interfaceClass, annotatedServiceBeanName); // ServiceBean Bean name 默认是接口类的权限定名 String beanName = generateServiceBeanName(service, interfaceClass, annotatedServiceBeanName); if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean registry.registerBeanDefinition(beanName, serviceBeanDefinition); if (logger.isInfoEnabled()) { logger.warn("The BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean has been registered with name : " + beanName); } } else { if (logger.isWarnEnabled()) { logger.warn("The Duplicated BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean[ bean name : " + beanName + "] was be found , Did @DubboComponentScan scan to same package in many times?"); } } } /** * Generates the bean name of {@link ServiceBean} * * @param service * @param interfaceClass the class of interface annotated {@link Service} * @param annotatedServiceBeanName the bean name of annotated {@link Service} * @return [email protected]#annotatedServiceBeanName * @since 2.5.9 */ private String generateServiceBeanName(Service service, Class<?> interfaceClass, String annotatedServiceBeanName) { ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, interfaceClass, environment); return builder.build(); } private Class<?> resolveServiceInterfaceClass(Class<?> annotatedServiceBeanClass, Service service) { Class<?> interfaceClass = service.interfaceClass(); if (void.class.equals(interfaceClass)) { interfaceClass = null; String interfaceClassName = service.interfaceName(); if (StringUtils.hasText(interfaceClassName)) { if (ClassUtils.isPresent(interfaceClassName, classLoader)) { interfaceClass = resolveClassName(interfaceClassName, classLoader); } } } if (interfaceClass == null) { Class<?>[] allInterfaces = annotatedServiceBeanClass.getInterfaces(); if (allInterfaces.length > 0) { interfaceClass = allInterfaces[0]; } } Assert.notNull(interfaceClass, "@Service interfaceClass() or interfaceName() or interface class must be present!"); Assert.isTrue(interfaceClass.isInterface(), "The type that was annotated @Service is not an interface!"); return interfaceClass; } private Class<?> resolveClass(BeanDefinitionHolder beanDefinitionHolder) { BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition(); return resolveClass(beanDefinition); } private Class<?> resolveClass(BeanDefinition beanDefinition) { String beanClassName = beanDefinition.getBeanClassName(); return resolveClassName(beanClassName, classLoader); } private Set<String> resolvePackagesToScan(Set<String> packagesToScan) { // linkedHashSet有序去重 Set<String> resolvedPackagesToScan = new LinkedHashSet<String>(packagesToScan.size()); for (String packageToScan : packagesToScan) { if (StringUtils.hasText(packageToScan)) { // 可以是占位符 String resolvedPackageToScan = environment.resolvePlaceholders(packageToScan.trim()); resolvedPackagesToScan.add(resolvedPackageToScan); } } return resolvedPackagesToScan; } private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class<?> interfaceClass, String annotatedServiceBeanName) { BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class); AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); // @Service注解可以有这些属性值 String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol", "interface"); propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(service, environment, ignoreAttributeNames)); // References "ref" property to [email protected] Bean addPropertyReference(builder, "ref", annotatedServiceBeanName); // Set interface 设置interface对象的引用关系 builder.addPropertyValue("interface", interfaceClass.getName()); /** * Add {@link com.alibaba.dubbo.config.ProviderConfig} Bean reference */ // 设置provider对象的引用关系 String providerConfigBeanName = service.provider(); if (StringUtils.hasText(providerConfigBeanName)) { addPropertyReference(builder, "provider", providerConfigBeanName); } /** * Add {@link com.alibaba.dubbo.config.MonitorConfig} Bean reference */ // 设置monitor对象的引用关系 String monitorConfigBeanName = service.monitor(); if (StringUtils.hasText(monitorConfigBeanName)) { addPropertyReference(builder, "monitor", monitorConfigBeanName); } /** * Add {@link com.alibaba.dubbo.config.ApplicationConfig} Bean reference */ // 设置application对象的引用关系 String applicationConfigBeanName = service.application(); if (StringUtils.hasText(applicationConfigBeanName)) { addPropertyReference(builder, "application", applicationConfigBeanName); } /** * Add {@link com.alibaba.dubbo.config.ModuleConfig} Bean reference */ // 设置module对象的引用关系 String moduleConfigBeanName = service.module(); if (StringUtils.hasText(moduleConfigBeanName)) { addPropertyReference(builder, "module", moduleConfigBeanName); } /** * Add {@link com.alibaba.dubbo.config.RegistryConfig} Bean reference */ // 设置registries对象的引用关系 String[] registryConfigBeanNames = service.registry(); List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames); if (!registryRuntimeBeanReferences.isEmpty()) { builder.addPropertyValue("registries", registryRuntimeBeanReferences); } /** * Add {@link com.alibaba.dubbo.config.ProtocolConfig} Bean reference */ // 设置protocols对象的引用关系 String[] protocolConfigBeanNames = service.protocol(); List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames); if (!protocolRuntimeBeanReferences.isEmpty()) { builder.addPropertyValue("protocols", protocolRuntimeBeanReferences); } return builder.getBeanDefinition(); } private ManagedList<RuntimeBeanReference> toRuntimeBeanReferences(String... beanNames) { ManagedList<RuntimeBeanReference> runtimeBeanReferences = new ManagedList<RuntimeBeanReference>(); if (!ObjectUtils.isEmpty(beanNames)) { for (String beanName : beanNames) { String resolvedBeanName = environment.resolvePlaceholders(beanName); runtimeBeanReferences.add(new RuntimeBeanReference(resolvedBeanName)); } } return runtimeBeanReferences; } private void addPropertyReference(BeanDefinitionBuilder builder, String propertyName, String beanName) { String resolvedBeanName = environment.resolvePlaceholders(beanName); builder.addPropertyReference(propertyName, resolvedBeanName); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { } @Override public void setEnvironment(Environment environment) { this.environment = environment; } @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } @Override public void setBeanClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } }