继续上篇内容,本篇讲解服务启动时,动态注入相关的实例。
一.自定义注解
自定义的注解分为三部分:
- 容器启动时,自动注入配置的注解
- 服务端注入服务提供者的注解
- 消费端启动引用服务提供者的注解
@EnableRainRpc 自动扫包,引入一些默认配置,以及注入RainRpcComponentScanRegistrar,使注解了@RainProvider, @RainConsumer 的类生效。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({RainRpcComponentScanRegistrar.class, RainRpcConfig.class,RainRpcAutoConfiguration.class })
public @interface EnableRainRpc {
String[] value() default {};
Class<?>[] basePackageClasses() default {};
}
@RainProvider 用于标识服务提供者的具体实现类
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Inherited
public @interface RainProvider {
}
@RainConsumer标识服务提供者的接口,用于消费者引用
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Inherited
public @interface RainConsumer {
String name() default "";
String cluster() default "rpc";
String degradation() default "";
long timeout() default 10;
}
二.定制beanDefinition后置处理器
RainRpcComponentScanRegistrar 实现了spring的ImportBeanDefinitionRegistrar 接口,可以动态注册 beanDefinition。容器启动时,会执行registerBeanDefinitions方法。
public class RainRpcComponentScanRegistrar implements ImportBeanDefinitionRegistrar , ResourceLoaderAware
, EnvironmentAware, BeanClassLoaderAware {
protected final Log logger = LogFactory.getLog(getClass());
private ResourceLoader resourceLoader;
private Environment environment;
private ClassLoader classLoader;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
registerProviderBeanPostProcessor(packagesToScan, registry);
registerConsumerBeanPostProcessor(packagesToScan,registry);
}
public void registerProviderBeanPostProcessor(Set<String> packagesToScan,BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = rootBeanDefinition(RainProviderBeanPostProcessor.class);
builder.addConstructorArgValue(packagesToScan);
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
public void registerConsumerBeanPostProcessor(Set<String> packagesToScan,BeanDefinitionRegistry registry) {
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(RainConsumer.class));
for (String basePackage : packagesToScan) {
Set<BeanDefinition> candidateComponents = scanner
.findCandidateComponents(basePackage);
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
if (!annotationMetadata.isInterface()) {
logger.info("@RainConsumer can only be specified on an interface");
continue;
}
registerClient(beanDefinition, registry);
}
}
}
}
private void registerClient(AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) {
Class<?> beanClass = resolveClass(beanDefinition);
RainConsumer service = findAnnotation(beanClass, RainConsumer.class);
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, beanClass);
registry.registerBeanDefinition(beanClass.getName(), serviceBeanDefinition);
}
private AbstractBeanDefinition buildServiceBeanDefinition(RainConsumer service, Class<?> interfaceClass) {
BeanDefinitionBuilder builder = rootBeanDefinition(ConsumerBean.class);
builder.addPropertyValue("interfaceClass", interfaceClass.getName());
builder.addPropertyValue("annotation", service);
builder.setPrimary(Boolean.TRUE);
return builder.getBeanDefinition();
}
private Class<?> resolveClass(AnnotatedBeanDefinition beanDefinition) {
String beanClassName = beanDefinition.getBeanClassName();
return resolveClassName(beanClassName, classLoader);
}
private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(EnableRainRpc.class.getName()));
Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
String[] value = attributes.getStringArray("value");
Set<String> packagesToScan = new LinkedHashSet<String>(Arrays.asList(value));
for (Class<?> basePackageClass : basePackageClasses) {
packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
}
if (packagesToScan.isEmpty()) {
return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));
}
return packagesToScan;
}
protected ClassPathScanningCandidateComponentProvider getScanner() {
return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
@Override
protected boolean isCandidateComponent(
AnnotatedBeanDefinition beanDefinition) {
boolean isCandidate = false;
if (beanDefinition.getMetadata().isIndependent()) {
if (!beanDefinition.getMetadata().isAnnotation()) {
isCandidate = true;
}
}
return isCandidate;
}
};
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
}
1. 处理@RainProvider的bean
registerProviderBeanPostProcessor方法主要是向bean注册器中注册RainProviderBeanPostProcessor后置处理器。 RainProviderBeanPostProcessor处理流程:
- 获取扫包路基,路径来源注解@EnableRainRpc启动类路径或@EnableRainRpc自定义的路径
- 扫描标注@RainProvider注解的beanDefinition
- 根据beanDefinition构造ProviderBean
- 将ProviderBean注册到bean注册器中
public class RainProviderBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware
, BeanClassLoaderAware {
protected final Log logger = LogFactory.getLog(getClass());
private final Set<String> packagesToScan;
private Environment environment;
private ClassLoader classLoader;
public RainProviderBeanPostProcessor(Collection<String> packagesToScan) {
this(new LinkedHashSet<>(packagesToScan));
}
public RainProviderBeanPostProcessor(Set<String> packagesToScan) {
this.packagesToScan = packagesToScan;
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
registerServiceBeans(resolvedPackagesToScan, registry);
}
}
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, false);
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
scanner.addIncludeFilter(new AnnotationTypeFilter(RainProvider.class));
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);
}
}
}
}
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;
}
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;
}
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry) {
Class<?> beanClass = resolveClass(beanDefinitionHolder);
RainProvider service = findAnnotation(beanClass, RainProvider.class);
Class<?> interfaceClass = beanClass.getInterfaces()[0];
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, interfaceClass, annotatedServiceBeanName);
registry.registerBeanDefinition( interfaceClass.getName(), serviceBeanDefinition);
}
private Class<?> resolveClass(BeanDefinitionHolder beanDefinitionHolder) {
BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
String beanClassName = beanDefinition.getBeanClassName();
return resolveClassName(beanClassName, classLoader);
}
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;
}
private AbstractBeanDefinition buildServiceBeanDefinition(RainProvider service, Class<?> interfaceClass,
String annotatedServiceBeanName) {
BeanDefinitionBuilder builder = rootBeanDefinition(ProviderBean.class);
addPropertyReference(builder, "ref", annotatedServiceBeanName);
builder.addPropertyValue("interfaceClass", interfaceClass.getName());
builder.addPropertyValue("methodList", interfaceClass.getDeclaredMethods());
return builder.getBeanDefinition();
}
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 setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
}
2. 处理@RainConsumer的bean
区别于@RainProvider的处理方式,@RainConsumer的处理换了一种方式,为啥会这样呢? @RainConsumer注解对象都是接口,直接使用ClassPathBeanDefinitionScanner扫描器,不会将接口类转换为beanDefinition,故而不能使用beanDefinition后置处理器处理。 既然现成的扫描器实现不了目标,那就自定义一个扫描器,重写判断条件。 代码如下:
protected ClassPathScanningCandidateComponentProvider getScanner() {
return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
@Override
protected boolean isCandidateComponent(
AnnotatedBeanDefinition beanDefinition) {
boolean isCandidate = false;
if (beanDefinition.getMetadata().isIndependent()) {
if (!beanDefinition.getMetadata().isAnnotation()) {
isCandidate = true;
}
}
return isCandidate;
}
};
}
有了扫描器之后,操作方式就跟@RainProvider类似:
- 扫描对应路径下的注解了@RainConsumer类获取BeanDefinition
- 根据beanDefinition构造一个ConsumerBean
- 将ConsumerBean注册到bean注册器中
这里ConsumerBean是一个FactoryBean,用于连接服务,生成代理服务类。
三.自动配置
RainRpcAutoConfiguration 向容器中注入ProviderContextStart。ProviderContextStart用于向注册中心注册服务。
@Configuration
public class RainRpcAutoConfiguration {
@Bean
public ProviderContextStart providerContextStart() {
return new ProviderContextStart();
}
}
项目详细代码参考
|