🌹🌹若是您以爲個人文章對您有幫助的話,記得在GitHub上star一波哈🌹🌹php
🌹🌹GitHub_awesome-it-blog 🌹🌹java
Motan是新浪微博研發並開源的一個RPC框架,與Dubbo相比,他更輕量級一些,代碼也更少一些,但也五臟俱全。git
Motan在GitHub上的項目地址:github.com/weibocom/mo…github
關於Motan的使用,能夠看官方Wiki:github.com/weibocom/mo…spring
基於Xml和基於Annotation的使用方式這裏再也不贅述,下面主要關注他是如何解析的。api
首先咱們要知道的是,Spring是如何識別、解析Xml文件中那一大堆標籤的。微信
這裏給出一個Xml的示例:網絡
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:motan="http://api.weibo.com/schema/motan" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://api.weibo.com/schema/motan http://api.weibo.com/schema/motan.xsd">
<!-- reference to the remote service -->
<motan:referer id="remoteService" interface="quickstart.FooService" directUrl="localhost:8002"/>
</beans>
複製代碼
Xml文件經過xmlns定義命名空間,好比這裏的 <motan:referer ... >
標籤就是經過 xmlns:motan="http://api.weibo.com/schema/motan"
來定義的。框架
那麼,寫了這些東西后,Spring如何識別motan標籤呢?ide
在Spring啓動時會自動掃描 classpath
下的 META-INF/spring.handlers
文件,在motan中,此文件在motan-core下:
motan-core/src/main/resources/META-INF/spring.handlers
複製代碼
此文件中定義了motan標籤的解析器:
http\://api.weibo.com/schema/motan=com.weibo.api.motan.config.springsupport.MotanNamespaceHandler
複製代碼
到這裏能夠發現,其實 xmlns:motan
的值,就是 spring.handlers
中配置的key,Spring就能夠經過這個能夠找到解析器 MotanNamespaceHandler
。
MotanNamespaceHandler在 motan-springsupport
工程下,它的實現以下:
public class MotanNamespaceHandler extends NamespaceHandlerSupport {
public final static Set<String> protocolDefineNames = new ConcurrentHashSet<String>();
public final static Set<String> registryDefineNames = new ConcurrentHashSet<String>();
public final static Set<String> basicServiceConfigDefineNames = new ConcurrentHashSet<String>();
public final static Set<String> basicRefererConfigDefineNames = new ConcurrentHashSet<String>();
@Override
public void init() {
registerBeanDefinitionParser("referer", new MotanBeanDefinitionParser(RefererConfigBean.class, false));
registerBeanDefinitionParser("service", new MotanBeanDefinitionParser(ServiceConfigBean.class, true));
registerBeanDefinitionParser("protocol", new MotanBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("registry", new MotanBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("basicService", new MotanBeanDefinitionParser(BasicServiceInterfaceConfig.class, true));
registerBeanDefinitionParser("basicReferer", new MotanBeanDefinitionParser(BasicRefererInterfaceConfig.class, true));
registerBeanDefinitionParser("spi", new MotanBeanDefinitionParser(SpiConfigBean.class, true));
registerBeanDefinitionParser("annotation", new MotanBeanDefinitionParser(AnnotationBean.class, true));
Initializable initialization = InitializationFactory.getInitialization();
// 這裏用於初始化SPI擴展點,本文暫不介紹。
initialization.init();
}
}
複製代碼
它繼承於Spring中的 NamespaceHandlerSupport
,並實現 init()
了方法,此方法用於初始化標籤解析器。
調用 NamespaceHandlerSupport
的 registerBeanDefinitionParser
方法,可完成解析器的註冊,motan統一用 MotanBeanDefinitionParser
做爲解析器,經過不一樣的參數來處理不一樣的標籤。 MotanBeanDefinitionParser
繼承於Spring的 BeanDefinitionParser
,並實現了其 parse()
方法,這個方法就會在解析Xml文件時,將遇到的element解析並生成BeanDefinition,並將其註冊到上下文的 BeanDefinitionRegistry
中,最終完成Xml的解析。
有兩種方式開啓Annotation模式:
使用這兩種方式都會生成 AnnotationBean
,並將其注入到Spring容器中。
此方式依然是經過 META-INF/spring.handlers
完成的。
因爲容器啓動須要掃描此文件,在上文描述中,指定的 MotanNamespaceHandler
中的 init()
方法,經過如下代碼提供了annotation這個element的解析:
@Override
public void init() {
// ...
registerBeanDefinitionParser("annotation", new MotanBeanDefinitionParser(AnnotationBean.class, true));
// ...
}
複製代碼
而後在Xml配置中配置:
<motan:annotation package="xxx.xxx.xx"/>
複製代碼
就能夠掃描指定package下面的類了。
經過如下方式掃描package指定的類:
@Bean
public AnnotationBean motanAnnotationBean() {
AnnotationBean motanAnnotationBean = new AnnotationBean();
motanAnnotationBean.setPackage("xxx.xxx.xx");
return motanAnnotationBean;
}
複製代碼
motan有兩個核心註解:
其中,@MotanService
用於標識某個類是一個motan服務實現類,MotanReferer
用於標識服務調用方。
典型的使用方式以下:
public interface MotanDemoService {
String hello(name);
}
複製代碼
@MotanService(/* protocol、registry 等配置 */)
public class MotanDemoServiceImpl implements MotanDemoService {
public String hello(String name) {
System.out.println(name);
return "Hello " + name + "!";
}
}
複製代碼
@MotanReferer(/* 配置 */)
private MotanDemoService service;
複製代碼
將 AnnotationBean
注入到容器時,motan經過Spring提供的功能介入了Bean的生命週期,來完成註解的掃描。
來看一下 AnnotationBean
的定義:
public class AnnotationBean implements DisposableBean, BeanFactoryPostProcessor, BeanPostProcessor, BeanFactoryAware, Ordered {
// ...
}
複製代碼
最關鍵的在於 BeanFactoryPostProcessor
和 BeanPostProcessor
。對他倆作個簡單介紹:
引用一個網絡上的圖來描述一下這兩個接口介入的時機:
按照順序,首先看一下 BeanFactoryPostProcessor
的 postProcessBeanFactory
都幹了啥。
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (annotationPackage == null || annotationPackage.length() == 0) {
return;
}
if (beanFactory instanceof BeanDefinitionRegistry) {
try {
// 初始化類掃描器
Class<?> scannerClass = ClassUtils.forName("org.springframework.context.annotation.ClassPathBeanDefinitionScanner",
AnnotationBean.class.getClassLoader());
// 實例化類掃描器
Object scanner = scannerClass.getConstructor(new Class<?>[]{BeanDefinitionRegistry.class, boolean.class})
.newInstance(new Object[]{(BeanDefinitionRegistry) beanFactory, true});
// 初始化註解類型過濾器,在包掃描的過程當中,知足指定條件註解的class會被加載
Class<?> filterClass = ClassUtils.forName("org.springframework.core.type.filter.AnnotationTypeFilter",
AnnotationBean.class.getClassLoader());
// 設置要匹配的註解:@MotanService,即暴露motan服務的類
Object filter = filterClass.getConstructor(Class.class).newInstance(MotanService.class);
Method addIncludeFilter = scannerClass.getMethod("addIncludeFilter",
ClassUtils.forName("org.springframework.core.type.filter.TypeFilter", AnnotationBean.class.getClassLoader()));
// 設置"包含"過濾器,只有包含上面指定的@MotanService註解時,才加載
addIncludeFilter.invoke(scanner, filter);
// 執行掃描
Method scan = scannerClass.getMethod("scan", new Class<?>[]{String[].class});
scan.invoke(scanner, new Object[]{annotationPackages});
} catch (Throwable e) {
// spring 2.0
}
}
}
複製代碼
變量 annotationPackage
即上面設置的要掃描的包。代碼大意已在註釋中給出。這段代碼的做用,就是掃描指定的包,並將符合條件的class做爲Spring候選Bean,並將其BeanDefinition註冊到給定的BeanFactory或ApplicationContext中。
而後來看下 BeanPostProcessor
的兩個方法幹了啥。
BeanPostProcessor
有兩個方法:postProcessBeforeInitialization
和 postProcessAfterInitialization
。
postProcessBeforeInitialization
用於 init-mothod
方法執行前介入,postProcessAfterInitialization
在其後介入。兩個方法的實現以下:
/** * init reference field */
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!isMatchPackage(bean)) {
return bean;
}
Class<?> clazz = bean.getClass();
if (isProxyBean(bean)) {
clazz = AopUtils.getTargetClass(bean);
}
// ... 解析setter method上的@MotanReferer註解,省略 ...
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
// 獲取field上的MotanReferer註解,若是獲取到了,經過refer方法解析他
MotanReferer reference = field.getAnnotation(MotanReferer.class);
if (reference != null) {
Object value = refer(reference, field.getType());
if (value != null) {
field.set(bean, value);
}
}
} catch (Throwable t) {
throw new BeanInitializationException("Failed to init remote service reference at filed " + field.getName()
+ " in class " + bean.getClass().getName(), t);
}
}
return bean;
}
複製代碼
/** * init service config and export servcice */
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (!isMatchPackage(bean)) {
return bean;
}
Class<?> clazz = bean.getClass();
if (isProxyBean(bean)) {
clazz = AopUtils.getTargetClass(bean);
}
// 獲取class上的@MotanService註解,並解析
MotanService service = clazz.getAnnotation(MotanService.class);
if (service != null) {
ServiceConfigBean<Object> serviceConfig = new ServiceConfigBean<Object>();
// ... 初始化ServiceConfigBean,省略 ...
}
return bean;
}
複製代碼
postProcessBeforeInitialization
方法用於解析Bean中帶有@MotanReferer註解的setter方法或field,並完成調用方的初始化。
postProcessAfterInitialization
方法用於解析帶有@MotanService註解的class,並將這個class做爲motan服務註冊到註冊中心,暴露爲服務。
motan也有原生的服務暴露形式,本文沒有介紹,具體能夠參考官方wiki。
motan主要利用Spring啓動時加載並初始化 META-INF/spring.handlers
來完成與Spring的集成。
在xml配置形式下,motan用 MotanNamespaceHandler
完成標籤解析器的註冊。
在Annotation配置形式下,motan主要利用 BeanFactoryPostProcessor
和 BeanPostProcessor
介入Bean生命週期,用 BeanFactoryPostProcessor
實現了class的掃描,用 BeanPostProcessor
實現了兩個核心註解 @MotanReferer
和 @MotanService
的解析。