ServiceClassPostProcessor
ServiceClassPostProcessor
postProcessBeanDefinitionRegistry
ServiceClassPostProcessor implements BeanDefinitionRegistryPostProcessor,实现该接口的两个方法,postProcessBeanFactory方法空实现,关键看postProcessBeanDefinitionRegistry,这个方法的作用是注册更多的bean到spring容器中,因为该方法有一个BeanDefinitionRegistry类型参数,BeanDefinitionRegistry提供了丰富的方法来操作bean定义,判断、注册、反注册等方法都准备好了,我们在编写postProcessBeanDefinitionRegistry方法的内容时,就能直接使用入参registry的这些方法来完成判断和注册、反注册等操作(当然ServiceClassPostProcessor这个bean要保证被注册到spring容器(以@Bean、xml都可以),才会调这个postProcessBeanDefinitionRegistry)。
方法主要三个操作:注册监听器、解析要扫描的包集合(resolvePackagesToScan)、注册bean(见registerServiceBeans)。
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 向registry注册DubboBootstrapApplicationListener监听器bean
registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME, DubboBootstrapApplicationListener.class);
// 内部利用 environment 对 placeHolder 解析
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!");
}
}
}
registerServiceBeans
(1)先创建DubboClassPathBeanDefinitionScanner,一会调用其scan进行包扫描并注册BeanDefinition。
(2)然后resolveBeanNameGenerator获取beanNameGenerator,并调用scanner.setBeanNameGenerator(beanNameGenerator),设置bean的名称生成器。
(3)然后scanner.addIncludeFilter设置哪些注解可以被扫描并处理。这些注解就是@DubboService、@Service、阿里@Service,正好我们使用的DubboClassPathBeanDefinitionScanner构造函数内部useDefaultFilters=false,即并不会处理原生的那些@Component、@Repository、@Service、@Controller、@ManagedBean、@Named注解。
(4)遍历包集合,scanner.scan(packageToScan) 进行包扫描并注册beanDefinition。
(5)调用findServiceBeanDefinitionHolders拿到步骤4注册的BeanDefinitionHolder集合,不为空的话遍历调用registerServiceBean再进行一次注册。
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
serviceAnnotationTypes.forEach(annotationType -> {
scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
});
for (String packageToScan : packagesToScan) {
scanner.scan(packageToScan);
Set<BeanDefinitionHolder> beanDefinitionHolders =
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
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 + "]");
}
}
}
}
registerServiceBean
我们前面scan注册了一些BeanDefinition,但是下面的逻辑是生成新的(Abstract)BeanDefinition并注册到容器。
(1)先调用resolveClass方法,将BeanDefinitionHolder里面的class先加载一下(如果没加载的话)并返回Class beanClass
(2)findServiceAnnotation然后拿到beanClass上的注解对象,注解的属性集合以AnnotationAttributes表示,调用DubboAnnotationUtils#resolveServiceInterfaceClass加载beanClass的接口类并返回赋值给interfaceClass。
(3)根据service注解对象本身、interfaceClass、beanName、serviceAnnotationAttributes调用generateServiceBeanName重新生成BeanDefinition并赋值给AbstractBeanDefinition serviceBeanDefinition 。
(4)生成 ServiceBean Bean name 并scanner.checkCandidate检查是否存在该serviceBeanDefinition,如果不存在则registry.registerBeanDefinition(beanName, serviceBeanDefinition);进行注册。
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
DubboClassPathBeanDefinitionScanner scanner) {
Class<?> beanClass = resolveClass(beanDefinitionHolder);
Annotation service = findServiceAnnotation(beanClass);
AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
// ServiceBean Bean name
String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
registry.registerBeanDefinition(beanName, serviceBeanDefinition);
if (logger.isInfoEnabled()) {
logger.info("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?");
}
}
}
findServiceAnnotation
findMergedAnnotation是spring的AnnotatedElementUtils类的方法,该方法的作用是在beanClass上查询annotationType类型注解,将查询出的多个annotationType类型注解属性合并到查询的第一个注解中,就是多个相同注解合并(一般beanClass上很少有多个相同类型注解,比如beanClass有多个@Service注解)。
Objects::nonNull是rt.jar的,该方法就是找到beanClass上第一个(findFirst)在serviceAnnotationTypes出现的注解。
private Annotation findServiceAnnotation(Class<?> beanClass) {
return serviceAnnotationTypes
.stream()
.map(annotationType -> findMergedAnnotation(beanClass, annotationType))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
findServiceBeanDefinitionHolders
扫描packageToScan路径下已注册的 beanDefinitions 集合, beanNameGenerator为AnnotationBeanNameGenerator,生成beanName,先判断注解上有没有显示设置beanName,没有的话,就以类名小写为beanName。BeanDefinitionHolder 就是 BeanDefinition + beanName。
private Set<BeanDefinitionHolder> findServiceBeanDefinitionHolders(
ClassPathBeanDefinitionScanner scanner, String packageToScan, BeanDefinitionRegistry registry,
BeanNameGenerator beanNameGenerator) {
Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(packageToScan);
Set<BeanDefinitionHolder> beanDefinitionHolders = new LinkedHashSet<>(beanDefinitions.size());
for (BeanDefinition beanDefinition : beanDefinitions) {
String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry);
BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, beanName);
beanDefinitionHolders.add(beanDefinitionHolder);
}
return beanDefinitionHolders;
}
resolveBeanNameGenerator
通过BeanDefinitionRegistry拿到BeanNameGenerator,先对registry instanceof SingletonBeanRegistry判断,满足后进行强转,然后取出CONFIGURATION_BEAN_NAME_GENERATOR这个bean,该bean类型为BeanNameGenerator,如果为null,那么使用 new AnnotationBeanNameGenerator(),该BeanNameGenerator类型主要是生成beanName,先判断注解上有没有显示设置beanName,没有的话,就以类名小写为beanName。
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;
}
generateServiceBeanName
AnnotationAttributes是spring的api AnnotationUtils#getAnnotationAttributes(xx)的返回值,就是把比如@Service、@Reference注解的属性值填充到返回的AnnotationAttributes对象中。然后就是调用ServiceBeanNameBuilder#create创建String serviceBeanName。eg : “ServiceBean:com.org.demo:1.0.0:lala”
private String generateServiceBeanName(AnnotationAttributes serviceAnnotationAttributes, Class<?> interfaceClass) {
ServiceBeanNameBuilder builder = create(interfaceClass, environment)
.group(serviceAnnotationAttributes.getString("group"))
.version(serviceAnnotationAttributes.getString("version"));
return builder.build();
}
resolveClass
BeanDefinitionHolder = BeanDefinition + beanName,resolveClassName(beanClassName, classLoader)的利用后者classLoader加载前面的beanClassName。
private Class<?> resolveClass(BeanDefinitionHolder beanDefinitionHolder) {
BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
String beanClassName = beanDefinition.getBeanClassName();
return resolveClassName(beanClassName, classLoader);
}
resolvePackagesToScan
很简单,就是利用environment.resolvePlaceholders把占位符解析下。
private Set<String> resolvePackagesToScan(Set<String> packagesToScan) {
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;
}
convertParameters
把字符串数组变成Map,这个是很常见的方法,URL类里面也有这个操作。先对长度是否是偶数判定,即要保证一对一对的,然后就是遍历数组,i+=2,步长为2,填充到map
private Map<String, String> convertParameters(String[] parameters) {
if (ArrayUtils.isEmpty(parameters)) {
return null;
}
if (parameters.length % 2 != 0) {
throw new IllegalArgumentException("parameter attribute must be paired with key followed by value");
}
Map<String, String> map = new HashMap<>();
for (int i = 0; i < parameters.length; i += 2) {
map.put(parameters[i], parameters[i + 1]);
}
return map;
}
toRuntimeBeanReferences
遍历beanNames,将每个beanName生成RuntimeBeanReference并用 ManagedList包装返回。
private ManagedList<RuntimeBeanReference> toRuntimeBeanReferences(String... beanNames) {
ManagedList<RuntimeBeanReference> runtimeBeanReferences = new ManagedList<>();
if (!ObjectUtils.isEmpty(beanNames)) {
for (String beanName : beanNames) {
String resolvedBeanName = environment.resolvePlaceholders(beanName);
runtimeBeanReferences.add(new RuntimeBeanReference(resolvedBeanName));
}
}
return runtimeBeanReferences;
}
下面对RuntimeBeanReference做一个解释,下面两篇来自其他文章
在Spring中,Bean的解析阶段,会把xml配制中的标签解析成Spring中的BeanDefinition对像,我们知道一个bean可能需要依赖其他的bean,在XML配置中可以表现为
<bean class="foo.bar.xxx"> <property name="referBeanName" ref="otherBeanName" /> </bean>
在Spring的解析段,其实容器中是没有依赖的Bean的实例的因此,那么这是这个被依赖的Bean如何在BeanDefinition中表示呢?
答案就是RuntimeBeanReference,在解析到依赖的Bean的时侯,解析器会依据依赖bean的name创建一个RuntimeBeanReference对像,将这个对像放入BeanDefinition的MutablePropertyValues中。
例如:上例中的依赖bean会被解析成
//我们知道foo.bar.xxx 被解析为一个beanDefiniton,假设为 xxxBeanDefinition reference = new RuntimeBeanReference("otherBeanName"); xxxBeanDefinition.getPropertyValues().addPropertyValue("referBeanName", reference);
在创建Bean时,需要将依赖解析成真正的在Spring容器中存在的Bean。这是在getBean时由AbstractAutowireCapableBeanFactory在applyPropertyValues方法中通过BeanDefinitionValueResolver来实现的。BeanDefinitionValueResolver将真正的依赖bean和referBeanName关联起来。
原文链接:http://www.voidcn.com/article/p-kpgsopuu-bqb.html
当我们需要动态注入Bean,并给该Bean的属性注入其他Bean时,比如在Mybatis和Spring的整合中,我们需要动态注入Mapper到spring容器中,而该Mapper如果需要执行SQL语句,还需要持有SqlSessionFactory的引用。但是我们注入时,可能对应的Bean还没有准备好,这时,我们就可以使用RuntimeBeanReference,以保持对实际Bean的引用。在Spring处理依赖关系时,最终会将该引用替换成实际生成的Bean对象。例如:
definition.getPropertyValues().add( "sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName) );
原文链接:https://blog.youkuaiyun.com/lichuangcsdn/article/details/89931460
addPropertyReference
给bean添加其依赖的其他bean,其他bean就是这里对beanName经过RuntimeBeanReference包装(beanName需要先用environment解析下),然后添加到原bean中。注意一个是BeanDefinitionBuilder,一个是BeanDefinition,前者是生成后者的。
private void addPropertyReference(BeanDefinitionBuilder builder, String propertyName, String beanName) {
String resolvedBeanName = environment.resolvePlaceholders(beanName);
builder.addPropertyReference(propertyName, resolvedBeanName);
}
// BeanDefinitionBuilder#addPropertyReference是spring的,其内容 如下,这个就是我们前面讲述的RuntimeBeanReference内容
public BeanDefinitionBuilder addPropertyReference(String name, String beanName) {
this.beanDefinition.getPropertyValues().add(name, new RuntimeBeanReference(beanName));
return this;
}
buildServiceBeanDefinition
这个方法是最最最重要的!!
(1)利用BeanDefinitionBuilder构建BeanDefinition。首先拿到一个代表ServiceBean.class的BeanDefinitionBuilder(rootBeanDefinition是BeanDefinitionBuilder的工厂方法,用以生成BeanDefinitionBuilder的,和我们前面介绍的ServicebeanNameBuilder的create方法一样,生成builder本身即可直接new,也可以利用工厂方法)。
(2)builder.getBeanDefinition()拿到AbstractBeanDefinition(肯定是实现BeanDefinition的抽象类),并拿到 AbstractBeanDefinition的”属性集合“即MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(),这个可以看下面的代码截图(srpring AbstractBeanDefinition#getPropertyValues),这点可以看出AbstractBeanDefinition有一个属性:MutablePropertyValues propertyValues,propertyValues存放了bean的所有属性值。
public MutablePropertyValues getPropertyValues() {
if (this.propertyValues == null) {
this.propertyValues = new MutablePropertyValues();
}
return this.propertyValues;
}
(3)然后propertyValues.addPropertyValues添加我们自己AnnotationPropertyValuesAdapter(AnnotationPropertyValuesAdapter的类型为PropertyValues)。AnnotationPropertyValuesAdapter之前我们解释过了,其会把serviceAnnotation注解的属性值填充到beanDefinition的propertyValues中。( ignoreAttributeNames表示这些属性不需要(处理并)填充到beanDefinition中)
(4)前面ignoreAttributeNames忽略了一些属性的处理,后面就是对这些属性特殊处理。手动addPropertyValue在ignoreAttributeNames的属性到beanDefinition中;对于一些依赖的bean类型属性,使用addPropertyReference方法进行添加,这个前面讲到了。
(5)最后 builder.getBeanDefinition()返回构建好了并填充了属性值的AbstractBeanDefinition。
这里说明下,前面的addPropertyValues 、addPropertyReference 其实最终调用的都是MutablePropertyValues#addPropertyValue方法!!最终所有的属性都会添加到AbstractBeanDefinition的属性MutablePropertyValues propertyValues中。
private AbstractBeanDefinition buildServiceBeanDefinition(Annotation serviceAnnotation,
AnnotationAttributes serviceAnnotationAttributes,
Class<?> interfaceClass,
String annotatedServiceBeanName) {
//BeanDefinitionBuilder#rootBeanDefinition, RootBeanDefinition可用于没有继承关系的Bean的创建
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol",
"interface", "interfaceName", "parameters");
propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotation, environment, ignoreAttributeNames));
// Set interface
builder.addPropertyValue("interface", interfaceClass.getName());
// Convert parameters into map
builder.addPropertyValue("parameters", convertParameters(serviceAnnotationAttributes.getStringArray("parameters")));
// Add methods parameters
List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get("methods"));
if (!methodConfigs.isEmpty()) {
builder.addPropertyValue("methods", methodConfigs);
}
// References "ref" property to annotated-@Service Bean
addPropertyReference(builder, "ref", annotatedServiceBeanName);
/**
* Add {@link org.apache.dubbo.config.ProviderConfig} Bean reference
*/
String providerConfigBeanName = serviceAnnotationAttributes.getString("provider");
if (StringUtils.hasText(providerConfigBeanName)) {
addPropertyReference(builder, "provider", providerConfigBeanName);
}
/**
* Add {@link org.apache.dubbo.config.MonitorConfig} Bean reference
*/
String monitorConfigBeanName = serviceAnnotationAttributes.getString("monitor");
if (StringUtils.hasText(monitorConfigBeanName)) {
addPropertyReference(builder, "monitor", monitorConfigBeanName);
}
/**
* Add {@link org.apache.dubbo.config.ApplicationConfig} Bean reference
*/
String applicationConfigBeanName = serviceAnnotationAttributes.getString("application");
if (StringUtils.hasText(applicationConfigBeanName)) {
addPropertyReference(builder, "application", applicationConfigBeanName);
}
/**
* Add {@link org.apache.dubbo.config.ModuleConfig} Bean reference
*/
String moduleConfigBeanName = serviceAnnotationAttributes.getString("module");
if (StringUtils.hasText(moduleConfigBeanName)) {
addPropertyReference(builder, "module", moduleConfigBeanName);
}
/**
* Add {@link org.apache.dubbo.config.RegistryConfig} Bean reference
*/
String[] registryConfigBeanNames = serviceAnnotationAttributes.getStringArray("registry");
List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames);
if (!registryRuntimeBeanReferences.isEmpty()) {
builder.addPropertyValue("registries", registryRuntimeBeanReferences);
}
/**
* Add {@link org.apache.dubbo.config.ProtocolConfig} Bean reference
*/
String[] protocolConfigBeanNames = serviceAnnotationAttributes.getStringArray("protocol");
List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames);
if (!protocolRuntimeBeanReferences.isEmpty()) {
builder.addPropertyValue("protocols", protocolRuntimeBeanReferences);
}
return builder.getBeanDefinition();
}
ServiceClassPostProcessorTest
ServiceClassPostProcessorTest
@ContextConfiguration 主要是加载配置文件或者加载配置类,这里我们是加载配置类。这两个配置类的里面@Bean注解都会注册相关bean到spring容器。
@TestPropertySource,主要是给spring context添加了两个kv配置属性(就像以往application.properties那样),注意packagesToScan属性值为${provider.package},Environment能解析出来。
@ExtendWith(SpringExtension.class)
@ContextConfiguration(
classes = {
ServiceAnnotationTestConfiguration2.class, // 注意
ServiceClassPostProcessorTest.class
})
@TestPropertySource(properties = {
"provider.package = org.apache.dubbo.config.spring.context.annotation.provider",
"packagesToScan = ${provider.package}",
})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class ServiceClassPostProcessorTest {
....
}
@Bean
public ServiceClassPostProcessor serviceClassPostProcessor2
(@Value("${packagesToScan}") String... packagesToScan) {
return new ServiceClassPostProcessor(packagesToScan);
}
注册了ServiceClassPostProcessor 这个bean到spring容器中,该bean的名称为serviceClassPostProcessor2。ServiceClassPostProcessor注册完成之后会触发ServiceClassPostProcessor#postProcessBeanDefinitionRegistry方法,该方法会进行更多bean的注册。(ServiceAnnotationTestConfiguration2 这个类里面也有很多bean的注册 注意下)
packagesToScan(org.apache.dubbo.config.spring.context.annotation.provider)包下的类有四个类,前三个如下。
DefaultHelloService
@Service
@DubboService
public class DefaultHelloService implements HelloService {
@Override
public String sayHello(String name) {
return "Greeting, " + name;
}
}
DemoServiceImpl
@org.apache.dubbo.config.annotation.Service(
version = "2.5.7",
application = "${demo.service.application}",
protocol = "${demo.service.protocol}",
registry = "${demo.service.registry}",
methods = @Method(timeout = 100,name = "sayName")
)
@Service
@Transactional
public class DemoServiceImpl implements DemoService {
@Override
public String sayName(String name) {
return "Hello," + name;
}
@Override
public Box getBox() {
throw new UnsupportedOperationException("For Purposes!");
}
}
HelloServiceImpl
@Service(interfaceName = "org.apache.dubbo.config.spring.api.HelloService")
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "Hello, " + name;
}
}
我们说过会包扫描会注册原始的BeanDefinition+基于ServiceBean.class生成的AbstractBeanDefinition(buildServiceBeanDefinition)。断点跟踪后发现ServiceClassPostProcesss#registerServiceBeans内部scanner.scan(packageToScan)的时候没有注册BeanDefinition,而是调用findServiceBeanDefinitionHolders才会注册(内部调用scanner.findCandidateComponents(packageToScan))。
ServiceClassPostProcesss#registerServiceBeans调用过scanner.addIncludeFilter(serviceAnnotationTypes),包里三个类的注解是在ServiceClassPostProcesss#serviceAnnotationTypes中的,所以能加载到。注意DemoServiceImpl类的注解里面有${},而我们把Environment传递给了DubboClassPathBDScanner,所以能从上下文取到解析到并填充。
我在test方法,对beanFactory.getBeanDefinitionNames(),发现最后的所有注册的beanName如下
0-4 是DubboClassPathBDScanner构造函数最后一步注册的后置处理器
5-6 是这两个测试类-配置类
7-11 是ServiceAnnotationTestConfiguration2注册的
12 是该测试类注册的
13 是ServiceClassPostProcesss#registerServiceBeans第一步注册的监听器
14-16 是包扫描注册的
17~18 是ServiceClassPostProcesss#registerServiceBean注册的,内部现场构建AbstractBeanDefinition,beanName就是之前ServiceBeanNameBuilder的规则。按道理扫描到的3个BeanDefinition,应该会再有3个基于ServiceBean.class的BeanDefinition(registerServiceBean),但是只有两个,原因是HelloServiceImpl和DefaultHelloService在registerServiceBean方法调用generateServiceBeanName生成的bean名称(接口都是HelloService)是一样,scanner.checkCandidate(beanName, serviceBeanDefinition)不会通过,所以不会重复注册)
result = {String[19]@4019}
0 = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"
1 = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"
2 = "org.springframework.context.annotation.internalCommonAnnotationProcessor"
3 = "org.springframework.context.event.internalEventListenerProcessor"
4 = "org.springframework.context.event.internalEventListenerFactory"
5 = "serviceAnnotationTestConfiguration2"
6 = "serviceClassPostProcessorTest"
7 = "dubbo-demo-application"
8 = "my-registry"
9 = "dubbo"
10 = "platformTransactionManager"
11 = "serviceClassPostProcessor"
12 = "serviceClassPostProcessor2"
13 = "dubboBootstrapApplicationListener"
14 = "defaultHelloService"
15 = "demoServiceImpl"
16 = "helloServiceImpl"
17 = "ServiceBean:org.apache.dubbo.config.spring.api.HelloService"
18 = "ServiceBean:org.apache.dubbo.config.spring.api.DemoService:2.5.7"
测试方法如下:
HelloService类型的bean有两个这是通过scanner.findCandidateComponents(packageToScan)拿到的
ServiceBean也有两个,这是通过registerServiceBean、buildServiceBeanDefinition生成的。
ServiceClassPostProcessor也有两个,这两个是两个测试类@Bean方式注入的。
@Test
public void test() {
Map<String, HelloService> helloServicesMap = beanFactory.getBeansOfType(HelloService.class);
Assertions.assertEquals(2, helloServicesMap.size());
Map<String, ServiceBean> serviceBeansMap = beanFactory.getBeansOfType(ServiceBean.class);
Assertions.assertEquals(2, serviceBeansMap.size());
Map<String, ServiceClassPostProcessor> beanPostProcessorsMap =
beanFactory.getBeansOfType(ServiceClassPostProcessor.class);
Assertions.assertEquals(2, beanPostProcessorsMap.size());
Assertions.assertTrue(beanPostProcessorsMap.containsKey("serviceClassPostProcessor"));
Assertions.assertTrue(beanPostProcessorsMap.containsKey("serviceClassPostProcessor2"));
}
获取ServiceBean.class类型的bean集合,有两个,前面我们讲过生成流程了,主要是包扫描加载原始的BeanDefinition之后(满足那三个注解的@DubboService…),还会调用registerServiceBean生成基于ServiceBean.class的BeanDefinition。
17 = “ServiceBean:org.apache.dubbo.config.spring.api.HelloService”
18 = “ServiceBean:org.apache.dubbo.config.spring.api.DemoService:2.5.7”
@Test
public void testMethodAnnotation() {
Map<String, ServiceBean> serviceBeansMap = beanFactory.getBeansOfType(ServiceBean.class);
Assertions.assertEquals(2, serviceBeansMap.size());
ServiceBean demoServiceBean = serviceBeansMap.get("ServiceBean:org.apache.dubbo.config.spring.api.DemoService:2.5.7");
Assertions.assertNotNull(demoServiceBean.getMethods());
}
ServiceAnnotationTestConfiguration2
ServiceAnnotationTestConfiguration2上面有一个注解:@PropertySource(“classpath:/META-INF/default.properties”)注解表示将这个配置文件的内容加载到spring context中(配置文件的内容见最后)。spring context中的配置属性,都能通过@Value( x x ) 取 到 , 可 以 看 最 后 一 个 s e r v i c e C l a s s P o s t P r o c e s s o r , 就 用 到 了 @ V a l u e ( " {xx})取到,可以看最后一个serviceClassPostProcessor,就用到了@Value(" xx)取到,可以看最后一个serviceClassPostProcessor,就用到了@Value("{packagesToScan}"),以往我们都是直接在类的属性上用@Value,从这里发现方法的参数上也能这么用。${packagesToScan}的内容在前面的ServiceClassPostProcessorTest 通过@TestPropertySource配置了packagesToScan属性。
然后这个类通过注解@Bean注册了几个bean,@Bean()括号内的就是bean的名称,没有指定的话就是方法名称(方法开头字母小写)。 @Primary表示优先注册的。注册的bean如下
7 = "dubbo-demo-application"
8 = "my-registry"
9 = "dubbo"
10 = "platformTransactionManager"
11 = "serviceClassPostProcessor"
@Bean(“dubbo-demo-application”) 上面的注释可以提现,注册bean到容器可以通过xml配置也可能通过@Bean。
@PropertySource("classpath:/META-INF/default.properties")
public class ServiceAnnotationTestConfiguration2 {
/**
* Current application configuration, to replace XML config: 当前应用程序配置,以替换XML配置:
* <prev>
* <dubbo:application name="dubbo-demo-application"/>
* </prev>
*
* @return {@link ApplicationConfig} Bean
*/
@Bean("dubbo-demo-application")
public ApplicationConfig applicationConfig() {
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("dubbo-demo-application");
return applicationConfig;
}
@Bean("my-registry")
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("N/A");
return registryConfig;
}
@Bean("dubbo")
public ProtocolConfig protocolConfig() {
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setName("dubbo");
protocolConfig.setPort(12345);
return protocolConfig;
}
@Primary
@Bean
public PlatformTransactionManager platformTransactionManager() {
return new PlatformTransactionManager() {
@Override
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
return null;
}
@Override
public void commit(TransactionStatus status) throws TransactionException {
}
@Override
public void rollback(TransactionStatus status) throws TransactionException {
}
};
}
@Bean
public ServiceClassPostProcessor serviceClassPostProcessor(@Value("${packagesToScan}") String... packagesToScan) {
return new ServiceClassPostProcessor(packagesToScan);
}
}
default.properties 如下,这个配置文件的内容会加载到spring context,而DemoServiceImpl(的注解)正好有这几个属性值,DubboClassPathBeanDefinitionScanner在扫描到DemoServiceImpl会用Environment解析并填充。
demo.service.version = 2.5.7
demo.service.application = dubbo-demo-application
demo.service.protocol = dubbo
demo.service.registry = my-registry