1.今天 我们要实现dubbo的三个功能:
2.代码实现
总所周知,spring提供让我们自定义标签的功能(不懂的,自己google),dubbo是这样使用它的:
建立三个文件 (文件内容,后面会提供下载):
src/META-INF/dubbo.xsd
src/META-INF/spring.handlers
src/META-INF/spring.schemas
spring初始化自定义标签会回调NamespaceHandlerSupport的 init方法
/***
* spring 解析 标签执行
*
* @author HadLuo
* @since JDK1.7
* @history 2018年5月2日 新建
*/
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// 标签
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationBean.class));
// 标签
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryBean.class));
// 标签
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolBean.class));
// 标签
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class));
}
}
DubboBeanDefinitionParser 解析器,spring会自动调用parse方法
public class DubboBeanDefinitionParser implements BeanDefinitionParser {
private Class> beanClass;
private static final DubboIdStrategy ID_STRATEGY = new DubboIdStrategy();
public DubboBeanDefinitionParser(Class> beanClass) {
this.beanClass = beanClass;
}
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 动态注入 spring bean
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);
String id = element.getAttribute("id");
if (id == null || id.isEmpty()) {
// dubbo标签中没有id属性的 , 生成一个不重复的id
id = IdGenerator.generateId(ID_STRATEGY, beanClass);
}
if (parserContext.getRegistry().containsBeanDefinition(id)) {
// spring 有这个id 的bean 了 直接抛出异常
throw new IllegalStateException("Duplicate spring bean id " + id);
}
// 将 dubbo标签bean 注入spring
parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
// 为 dubbo标签bean设置属性值 , 这里不同于dubbo源码(源码太繁琐了), 这里直接 用反射 设置基本类型值,利用holder来设置 属性为 dubbo bean对象 的值
for (Field field : ReflectUtils.getAllFieldsByAnnotation(beanClass, Tag.class)) {
String tag = field.getAnnotation(Tag.class).value();
Class> holderClass = field.getAnnotation(Tag.class).holder();
beanDefinition.getPropertyValues().addPropertyValue(field.getName(),
getValueByType(field, element.getAttribute(tag),holderClass));
}
return beanDefinition;
}
/***
* 设置字段值
*
* @param field
* @param target
* @param val
* @throws NumberFormatException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @author HadLuo 2018年4月13日 新建
*/
@SuppressWarnings("rawtypes")
private static Object getValueByType(Field field, String val,Class> holderClass) {
if (val == null) {
return null;
}
if (field.getType().equals(Integer.class) || field.getType().equals(int.class)) {
return Integer.parseInt(val);
} else if (field.getType().equals(Boolean.class) || field.getType().equals(boolean.class)) {
return Boolean.parseBoolean(val);
} else if (field.getType().equals(Byte.class) || field.getType().equals(byte.class)) {
return Byte.parseByte(val);
} else if (field.getType().equals(Character.class) || field.getType().equals(char.class)) {
return val.charAt(0);
} else if (field.getType().equals(Double.class) || field.getType().equals(double.class)) {
return Double.parseDouble(val);
} else if (field.getType().equals(Float.class) || field.getType().equals(float.class)) {
return Float.parseFloat(val);
} else if (field.getType().equals(Long.class) || field.getType().equals(long.class)) {
return Long.parseLong(val);
} else if (field.getType().equals(Short.class) || field.getType().equals(short.class)) {
return Short.parseShort(val);
} else if (field.getType().equals(String.class)) {
return val;
} else if (ReflectUtils.isChild(field.getType(), Holder.class)) {
// 代表 是 对象 类型 , 从spring里面 找
String id = ID_STRATEGY.getFixBeanId(holderClass);
if (id == null || id.isEmpty()) {
throw new UnsupportedOperationException(field.getType().getName() + " 不能赋值为 :" + val);
}
// 用holder来 占位 , 后面初始化时 ,直接 利用spring context根据id来找dubbo bean
return new Holder(id);
}
throw new UnsupportedOperationException(field.getType().getName() + " 不能赋值为 :" + val);
}
}
ServiceBean 实现了spring bean的几个生命周期方法,同时继承了 ServiceConfig (service标签的配置值)
public class ServiceBean extends ServiceConfig implements SpringBeanLifecycle {
// 是否已经导出 ServiceBean 服务
private transient boolean exported;
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
if (exported) {
return;
}
setExported(true);
export();
}
}
@Override
public void afterPropertiesSet() throws Exception {
System.err.println("spring init " + ServiceBean.class.getName() + " bean");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
registerApplicationContext(applicationContext);
}
@Override
public void setBeanName(String name) {
}
public synchronized void setExported(boolean exported) {
this.exported = exported;
}
public synchronized boolean exported() {
return exported;
}
@Override
public void destroy() throws Exception {
setApplicationContext(null);
setExported(false);
}
}
ServiceConfig 配置信息类(包括实现导出)。
public class ServiceConfig extends AbstractConfig {
/** 服务接口全路径 Tag注解,是我自己实现的 不同于dubbo*/
@Tag("interface")
private String _interface;
/** 服务对象实现引用 */
@Tag("ref")
private String ref;
/** 远程服务调用超时时间(毫秒) */
@Tag("timeout")
private long timeout = 1000;
/** 负载均衡策略,可选值为:random(随机)、roundrobin(轮询)、leastactive(最少活跃调用) */
@Tag("loadbalance")
private String loadbalance = "random";
/** 是否缺省异步执行,不可靠的异步,只是忽略返回值,不阻塞执行线程 */
@Tag("async")
private boolean async = false;
/***holder 注入, 复杂对象****/
@Tag(holder = ApplicationBean.class)
private Holder applicationHolder;
/***holder 注入, 复杂对象****/
@Tag(holder = ProtocolBean.class)
private Holder protocolHolder;
public String getInterface() {
return _interface;
}
public String getRef() {
return ref;
}
public long getTimeout() {
return timeout;
}
public String getLoadbalance() {
return loadbalance;
}
public boolean isAsync() {
return async;
}
public void set_interface(String _interface) {
this._interface = _interface;
}
public void setRef(String ref) {
this.ref = ref;
}
public void setTimeout(long timeout) {
this.timeout = timeout;
}
public void setAsync(boolean async) {
this.async = async;
}
public void setApplicationHolder(Holder applicationHolder) {
this.applicationHolder = applicationHolder;
}
public void setProtocolHolder(Holder protocolHolder) {
this.protocolHolder = protocolHolder;
}
public void setLoadbalance(String loadbalance) {
this.loadbalance = loadbalance;
}
// dubbo://10.112.6.12:20880/cn.javacoder.test.dubbo.IHelloWorldService?application=test-provider
// &dubbo=2.5.3&interface=cn.javacoder.test.dubbo.IHelloWorldService&methods=say&pid=6816&side=provider×tamp=1522284835101
public void export() {
if (getApplicationContext() == null) {
throw new RuntimeException("spring 还没有初始化完成");
}
wakeupHolder();
// 这里 模拟 ======================
String url = "dubbo://" + "10.112.6.12:" + protocolHolder.get().getPort() + _interface + "?"
+ "application=" + applicationHolder.get().getName() + "&dubbo=2.5.3&interface=" + _interface
+ "&methods=say&pid=6816&side=provider×tamp=1522284835101";
System.err.println("准备开始 导出 >>" + url);
}
private void wakeupHolder() {
// 利用spring context 根据id 来找 dubbo bean标签
applicationHolder.setValue(getApplicationContext());
protocolHolder.setValue(getApplicationContext());
}
}
以上 就是 dubbo 简单的 service标签 的 查找和 导出,与dubbo源码实现思想基本一致,上面没有贴出工程源码,可以加我qq : 657455400 或者 自行下载:https://download.csdn.net/download/luozheng4698729/10387658