Dubbo 高性能升级版本,简单,高效
基于DUBBO 2.5.3构造
Github:https://github.com/xyp260466/dubbo-lite
主要升级及改动变化
1、去除所有坑余代码及不必要的扩展
2、分为 dubbo-common 与 dubbo-rpc两大主要模块
3、NIO网络传输层升级为Apache Mina(保留dubbo原始mina版本)
4、代理生成采用 dubbo-2.5.3原生 Javassist框架
5、序列化采用高性能框架 Protostuff-1.3.3 (相比hession提升90%,秒杀java-built-in)
6、保留部分核心
7、相比dubbo原始框架,代码结构清晰,有助于阅读及参考
8、欢迎积极扩展!
Protostuff Decoder & Encoder:
/* * Dubbo Mina Decoder Use Protostuff * * */
package com.alibaba.dubbo.rpc.codec;
import com.alibaba.dubbo.rpc.remoting.Request;
import com.alibaba.dubbo.rpc.remoting.Response;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderAdapter;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
public class ProtostuffDubboDecoder extends ProtocolDecoderAdapter {
public void decode(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception {
InputStream stream = in.asInputStream();
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte b = (byte)stream.read();
int bf;
while((bf = stream.read()) != -1){
os.write(bf);
}
byte[] protoStuff = os.toByteArray();
if(b == 0x00){
Schema<Request> schema = RuntimeSchema
.getSchema(Request.class);
Request request = new Request();
ProtostuffIOUtil.mergeFrom(protoStuff, request, schema);
out.write(request);
}else if(b == 0x01){
Schema<Response> schema = RuntimeSchema
.getSchema(Response.class);
Response response = new Response();
ProtostuffIOUtil.mergeFrom(protoStuff, response, schema);
out.write(response);
}else{
throw new IllegalStateException("Cannot Support Read Type: "+b);
}
}
}
/* * Dubbo Mina Encoder Use Protostuff * * * */
package com.alibaba.dubbo.rpc.codec;
import com.alibaba.dubbo.rpc.remoting.Request;
import com.alibaba.dubbo.rpc.remoting.Response;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
public class ProtostuffDubboEncoder extends ProtocolEncoderAdapter {
/** * encode * * @param session * @param message * @param out * @throws Exception */
public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
ByteBuffer byteBuffer = ByteBuffer.allocate(4096);
byteBuffer.setAutoExpand(true);
if(message instanceof Request){
byteBuffer.put((byte)0x00);
Schema<Request> schema = RuntimeSchema
.getSchema(Request.class);
LinkedBuffer buffer = LinkedBuffer.allocate(1024);
byte[] protoStuff = ProtostuffIOUtil.toByteArray((Request)message, schema, buffer);
byteBuffer.put(protoStuff);
}else if(message instanceof Response){
byteBuffer.put((byte)0x01);
Schema<Response> schema = RuntimeSchema
.getSchema(Response.class);
LinkedBuffer buffer = LinkedBuffer.allocate(4096);
byte[] protoStuff = ProtostuffIOUtil.toByteArray((Response)message, schema, buffer);
byteBuffer.put(protoStuff);
}else{
throw new IllegalStateException("Cannot Support Class Type: "+message.getClass().getName());
}
byteBuffer.flip();
out.write(byteBuffer);
}
}
使用非常简单:
发布服务:
//initialize a protocol
Protocol protocol = DubboProtocol.getProtocol();
//export a service
protocol.export(new SimpleImpl(), Simple.class, 2880);
消费服务:
//initialize a protocol
Protocol protocol = DubboProtocol.getProtocol();
Simple invoker = protocol.refer(Simple.class, "127.0.0.1", 2880, 3600);
强大的与Spring基于注解的自动集成能力:
现在你会感觉Spring集成将会变的非常简单
在Spring配置文件中加入如下内容:
<dubbo:annotation-driven base-package="com"/>
系统将会自动将扫描到的Bean加入Spring容器并发布Dubbo服务,非常方便
Spring配置文件范例:
<?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:dubbo="http://code.xyp260466.com/schema/dubbo" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.xyp260466.com/schema/dubbo META-INF/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.xyp260466.dubbo.test.provider"/>
<dubbo:annotation-driven base-package="com.xyp260466.dubbo.test.provider"/>
</beans>
消费服务:加上@Consumer注解
@Consumer
private SimpleProvider simpleProvider;
发布服务:加上@Provider注解
@Provider
public class SimpleProviderImpl implements SimpleProvider
dubbo.xsd文件:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://code.xyp260466.com/schema/dubbo" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://code.xyp260466.com/schema/dubbo">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:annotation>
<xsd:documentation><![CDATA[ Namespace support for the dubbo services provided by dubbo framework. ]]></xsd:documentation>
</xsd:annotation>
<xsd:element name="annotation-driven">
<xsd:annotation>
<xsd:documentation><![CDATA[ Scans the classpath for annotated components that will be auto-registered as Spring beans. By default, the Dubbo-provided @Provider, @Interface, @Consumer stereotypes will be detected. ]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="base-package" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[ The comma-separated list of packages to scan for annotated components. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>
基于注解的Spring3.0集成实现部分:
package com.xyp260466.dubbo.schema;
import com.alibaba.dubbo.common.utils.ReflectUtils;
import com.xyp260466.dubbo.annotation.Provider;
import com.xyp260466.dubbo.annotation.Interface;
import com.xyp260466.dubbo.beans.ProviderBean;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.XmlReaderContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.ComponentScanBeanDefinitionParser;
import org.springframework.context.annotation.DubboClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import java.util.Map;
import java.util.Set;
/** * Created by xyp on 16-5-9. */
public class AutoBeanDefinitionParser extends ComponentScanBeanDefinitionParser {
private static final String BASE_PACKAGE_ATTRIBUTE = "base-package";
private static final Logger logger = Logger.getLogger(AutoBeanDefinitionParser.class);
public BeanDefinition parse(Element element, ParserContext parserContext) {
logger.info("Parse Dubbo Services.");
String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Assert.notEmpty(basePackages, "At least one base package must be specified");
DubboClassPathBeanDefinitionScanner scanner = new DubboClassPathBeanDefinitionScanner(parserContext);
Set<BeanDefinitionHolder> beanDefinitions = scanner.scanComplete(basePackages);
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
for(BeanDefinitionHolder holder : beanDefinitions){
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(ProviderBean.class);
beanDefinition.setLazyInit(false);
ScannedGenericBeanDefinition srcDefinition = (ScannedGenericBeanDefinition) holder.getBeanDefinition();
//process
RootBeanDefinition classDefinition = new RootBeanDefinition();
String beanClass = srcDefinition.getBeanClassName();
classDefinition.setBeanClass(ReflectUtils.forName(beanClass));
classDefinition.setLazyInit(false);
beanDefinition.setBeanClassName(ProviderBean.class.getName());
AnnotationMetadata metadata = srcDefinition.getMetadata();
Map<String, Object> attributes = metadata.getAnnotationAttributes(Provider.class.getName());
String[] interfaces = metadata.getInterfaceNames();
if(interfaces.length == 0){
throw new IllegalStateException("Class [ "+beanClass+" ] No Interfaces Detected!");
}else {
String interfaceTarget = null;
if(interfaces.length > 1){
for(String interfaceStr : interfaces){
Class clazz = ReflectUtils.forName(interfaceStr);
if(clazz.isAnnotationPresent(Interface.class)){
interfaceTarget = interfaceStr;
}
}
}else{
interfaceTarget = interfaces[0];
}
if(interfaceTarget == null){
throw new IllegalStateException("Class [ "+beanClass+" ] Cannot Find suitable Interface!");
}else {
String id = interfaceTarget;
int counter = 2;
while(parserContext.getRegistry().containsBeanDefinition(id)) {
id = interfaceTarget + (counter ++);
}
if (parserContext.getRegistry().containsBeanDefinition(id)) {
throw new IllegalStateException("Duplicate spring bean id " + id);
}
parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
beanDefinition.getPropertyValues().addPropertyValue("id", id);
beanDefinition.getPropertyValues().addPropertyValue("interfaceClass", interfaceTarget);
String refId = interfaceTarget;
if (attributes.size() > 0 && attributes.get("value") != null) {
refId = attributes.get("value").toString();
}
beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, refId));
}
}
}
return null;
}
protected void registerComponents(
XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {
Object source = readerContext.extractSource(element);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);
for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
}
// Register annotation config processors, if necessary.
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
}
readerContext.fireComponentRegistered(compositeDef);
}
}
Spring集成测试:
配置文件:
<?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:dubbo="http://code.xyp260466.com/schema/dubbo" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.xyp260466.com/schema/dubbo META-INF/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.xyp260466.dubbo.test.provider"/>
<dubbo:annotation-driven base-package="com.xyp260466"/>
</beans>
启动Spring容器:
package com.xyp260466.dubbo.test;
import org.apache.log4j.Logger;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/** * Created by xyp on 16-5-9. */
public class SpringTest {
private static final Logger logger = Logger.getLogger(SpringTest.class);
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
while (true){
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
}
}
}).start();
logger.info("spring container starting...");
new ClassPathXmlApplicationContext("spring-provider.xml");
}
}
测试客户端:
package com.xyp260466.dubbo.test;
import com.alibaba.dubbo.rpc.protocol.DubboProtocol;
import com.xyp260466.dubbo.test.provider.SimpleProvider;
import org.apache.log4j.Logger;
/** * Created by xyp on 16-5-10. */
public class CallSpringService {
private static final Logger logger = Logger.getLogger(CallSpringService.class);
public static void main(String[] args) {
logger.info("Start Calling Spring Dubbo Service......");
SimpleProvider simpleProvider = DubboProtocol.getProtocol().refer(SimpleProvider.class, "127.0.0.1", 20880);
System.out.println("Spring Dubbo Service Result: "+simpleProvider.providerMethod("xiaoming"));
}
}