> anoyi中的GrpcAutoConfiguration
1. 簡述
這個方法是讀取端口ip配置并執行啟動grpc的核心方法
2. 查看GrpcAutoConfiguration的注解
~~~
@Slf4j
@Configuration
@EnableConfigurationProperties(GrpcProperties.class)
~~~
這三個注解,一個slf4j日志,代表可以直接調用日志對象,一個是Configuration,代表是ico的配置類,一個是EnableConfigurationProperties,會自己動注入配置的實體
3. 分析GrpcProperties類
~~~
@Data
@ConfigurationProperties(prefix = "spring.grpc")
public class GrpcProperties {
/**
* enable server start
*/
private boolean enable;
/**
* server listen port
*/
private int port;
/**
* client config
*/
private List<RemoteServer> remoteServers;
/**
* client interceptor
*/
private Class clientInterceptor;
/**
* server interceptor
*/
private Class serverInterceptor;
}
~~~
這個類頭部有個兩個注解類,一個是Data代表該類自己生成get和set方法,一個是ConfigurationProperties,代表會去拿jvm里面的Properties的key前綴符合(prefix = "spring.grpc")的屬性,并實例化GrpcProperties ,把Properties符合條件的value值注入同名的屬性中。
4. 查看屬性
~~~
private final AbstractApplicationContext applicationContext;
private final GrpcProperties grpcProperties;
~~~
applicationContext是全局上下文的spring context,在構造方法調用的時候回自動注入,grpcProperties是在構造方法的時候自動注入
5. 查看構造方法(這個方法交給spring實例化,具體查看Configuration這個注解,這個注解會在ico容器初始化)
~~~
public GrpcAutoConfiguration(AbstractApplicationContext applicationContext, GrpcProperties grpcProperties) {
this.applicationContext = applicationContext;
this.grpcProperties = grpcProperties;
}
~~~
6. 一些bean的實現
~~~
/**
* 全局 RPC 序列化/反序列化
*/
@Bean
@ConditionalOnMissingBean(SerializeService.class)
public SerializeService serializeService() {
return new SofaHessianSerializeService();
}
/**
* PRC 服務調用
*/
@Bean
public CommonService commonService(SerializeService serializeService) {
return new CommonService(applicationContext, serializeService);
}
/**
* RPC 服務端
*/
@Bean
@ConditionalOnMissingBean(GrpcServer.class)
@ConditionalOnProperty(value = "spring.grpc.enable", havingValue = "true")
public GrpcServer grpcServer(CommonService commonService) throws Exception {
GrpcServer server = new GrpcServer(grpcProperties, commonService);
server.start();
return server;
}
/**
* RPC 客戶端
*/
@Bean
@ConditionalOnMissingBean(GrpcClient.class)
public GrpcClient grpcClient(SerializeService serializeService) {
GrpcClient client = new GrpcClient(grpcProperties, serializeService);
client.init();
return client;
}
~~~
ConditionalOnMissingBean意思是相應的配置的類如果不存在就不調用注解它的方法,ConditionalOnProperty注解的意思是必須滿足配置的value的相對應的Properties的value值等于havingValue 的值才能執行注解它的方法
7. 查看ExternalGrpcServiceScannerRegistrar類
~~~
/**
* 手動掃描 @GrpcService 注解的接口,生成動態代理類,注入到 Spring 容器
*/
public static class ExternalGrpcServiceScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private BeanFactory beanFactory;
private ResourceLoader resourceLoader;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
ClassPathBeanDefinitionScanner scanner = new ClassPathGrpcServiceScanner(registry);
scanner.setResourceLoader(this.resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(GrpcService.class));
Set<BeanDefinition> beanDefinitions = scanPackages(importingClassMetadata, scanner);
ProxyUtil.registerBeans(beanFactory, beanDefinitions);
}
/**
* 包掃描
*/
private Set<BeanDefinition> scanPackages(AnnotationMetadata importingClassMetadata, ClassPathBeanDefinitionScanner scanner) {
List<String> packages = new ArrayList<>();
Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(GrpcServiceScan.class.getCanonicalName());
if (annotationAttributes != null) {
String[] basePackages = (String[]) annotationAttributes.get("packages");
if (basePackages.length > 0) {
packages.addAll(Arrays.asList(basePackages));
}
}
Set<BeanDefinition> beanDefinitions = new HashSet<>();
if (CollectionUtils.isEmpty(packages)) {
return beanDefinitions;
}
packages.forEach(pack -> beanDefinitions.addAll(scanner.findCandidateComponents(pack)));
return beanDefinitions;
}
}
protected static class ClassPathGrpcServiceScanner extends ClassPathBeanDefinitionScanner {
ClassPathGrpcServiceScanner(BeanDefinitionRegistry registry) {
super(registry, false);
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
}
~~~
這個類在import注解配置中,所以會在spring啟動的時候初始化該類,該類實現了
BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware這三個類,
BeanFactoryAware提供bean工廠,
ImportBeanDefinitionRegistrar提供掃描包時候調用的registerBeanDefinitions方法,
ResourceLoaderAware提供setResourceLoader的方法
registerBeanDefinitions這個方法在spring啟動時候調用,
8. 查看registerBeanDefinitions方法
~~~
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
ClassPathBeanDefinitionScanner scanner = new ClassPathGrpcServiceScanner(registry);
scanner.setResourceLoader(this.resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(GrpcService.class));
Set<BeanDefinition> beanDefinitions = scanPackages(importingClassMetadata, scanner);
ProxyUtil.registerBeans(beanFactory, beanDefinitions);
}
~~~
這個方法有兩個參數AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,importingClassMetadata這個參數可以取得import注解的父注解的參數,registry是bean注冊器,
ClassPathGrpcServiceScanner是繼承ClassPathBeanDefinitionScanner的方法,這里new這個對象,并重構
isCandidateComponent的方法,這個是過濾類的方法,下面查看ClassPathGrpcServiceScanner類
~~~
protected static class ClassPathGrpcServiceScanner extends ClassPathBeanDefinitionScanner {
ClassPathGrpcServiceScanner(BeanDefinitionRegistry registry) {
super(registry, false);
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
}
~~~
這個類很簡單,然后registerBeanDefinitions這個方法會執行下面兩句語句,這個只是把掃描器添加過濾器,過濾掉沒有GrpcService注解的類
~~~
scanner.setResourceLoader(this.resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(GrpcService.class));
~~~
接下來registerBeanDefinitions方法會調用
~~~
Set<BeanDefinition> beanDefinitions = scanPackages(importingClassMetadata, scanner);
~~~
這個scanPackages可以掃描出符合條件的BeanDefinition,具體scanPackages方法,可以看下面
~~~
/**
* 包掃描
*/
private Set<BeanDefinition> scanPackages(AnnotationMetadata importingClassMetadata, ClassPathBeanDefinitionScanner scanner) {
List<String> packages = new ArrayList<>();
Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(GrpcServiceScan.class.getCanonicalName());
if (annotationAttributes != null) {
String[] basePackages = (String[]) annotationAttributes.get("packages");
if (basePackages.length > 0) {
packages.addAll(Arrays.asList(basePackages));
}
}
Set<BeanDefinition> beanDefinitions = new HashSet<>();
if (CollectionUtils.isEmpty(packages)) {
return beanDefinitions;
}
packages.forEach(pack -> beanDefinitions.addAll(scanner.findCandidateComponents(pack)));
return beanDefinitions;
}
~~~
這個scanPackages方法只是掃描符合ClassPathBeanDefinitionScanner 掃描器標準的packages包底下的類,并生成
BeanDefinition,接下來registerBeanDefinitions方法會調用ProxyUtil.registerBeans(beanFactory, beanDefinitions);這是代理的方法,接下來看看這個代理類
9. 查看ProxyUtil類
~~~
protected static class ProxyUtil {
static void registerBeans(BeanFactory beanFactory, Set<BeanDefinition> beanDefinitions) {
for (BeanDefinition beanDefinition : beanDefinitions) {
String className = beanDefinition.getBeanClassName();
if (StringUtils.isEmpty(className)) {
continue;
}
try {
// 創建代理類
Class<?> target = Class.forName(className);
Object invoker = new Object();
InvocationHandler invocationHandler = new GrpcServiceProxy<>(target, invoker);
Object proxy = Proxy.newProxyInstance(GrpcService.class.getClassLoader(), new Class[]{target}, invocationHandler);
// 注冊到 Spring 容器
String beanName = ClassNameUtils.beanName(className);
((DefaultListableBeanFactory) beanFactory).registerSingleton(beanName, proxy);
} catch (ClassNotFoundException e) {
log.warn("class not found : " + className);
}
}
}
}
~~~
這個類具體看registerBeans方法,這個方法有兩個參數BeanFactory beanFactory, Set<BeanDefinition> beanDefinitions,beanFactory是bean工廠,beanDefinitions是我們上面掃描的類,看樣子是要實例化bean了
接下來看看
```
InvocationHandler invocationHandler = new GrpcServiceProxy<>(target, invoker);
```
這個是實例化代理類,并傳入被代理類invoker,也就是我們的bean,然后是執行下面的方法
```
Object proxy = Proxy.newProxyInstance(GrpcService.class.getClassLoader(), new Class[]{target}, invocationHandler);
```
這個是調用動態代理newProxyInstance方法,返回invoker這個實例化的類,但是這時候動態代理可能已經重寫invoker這個的所有方法,實現aop了,具體怎么樣我們也不知道,也就是proxy 已經不是原本的類,接下來看下一步
```
String beanName = ClassNameUtils.beanName(className);
((DefaultListableBeanFactory) beanFactory).registerSingleton(beanName, proxy);
```
這里把我們的代理類注冊到spring bean中