/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.Node;
/**
* Invoker. (API/SPI, Prototype, ThreadSafe)
*
* @see com.alibaba.dubbo.rpc.Protocol#refer(Class, com.alibaba.dubbo.common.URL)
* @see com.alibaba.dubbo.rpc.InvokerListener
* @see com.alibaba.dubbo.rpc.protocol.AbstractInvoker
*/
public interface Invoker<T> extends Node {
/**
* get service interface.
*
* @return service interface.
*/
Class<T> getInterface();
/**
* invoke.
*
* @param invocation
* @return result
* @throws RpcException
*/
Result invoke(Invocation invocation) throws RpcException;
}
dubbo中通过将每一个服务类(Service)包装成一个Invoker对象,然后通过协议(比如RMI)发送到网络。这样每个协议类不需要面对各种不同的服务类了。
下面示例说明Invoker的作用:
首先创建一个服务接口类
package com.enjoy.service;
public interface DemoService {
String sayHello(String name);
}
为该类创建一个实现类
package com.enjoy.service;
public class DemoServiceImpl implements DemoService {
private String type = "test";
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public DemoServiceImpl() {
super();
}
public String sayHello(String name) {
System.out.println("hello " + name + ", type:" + type);
return "Hello, " + name;
}
}
实现一个Invoker类
package com.enjoy.protocol;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcResult;
import com.enjoy.service.DemoService;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* SimpleInvoker.
*/
public class SimpleInvoker<T> implements Invoker<T> {
private T target;
private Class<T> type;
private URL url;
public SimpleInvoker(T service, Class<T> type, URL url) {
this.target = service;
this.type = type;
this.url = url;
}
@Override
public Class<T> getInterface() {
return type;
}
@Override
public Result invoke(Invocation invocation) throws RpcException {
Method method = null;
try {
method = type.getMethod(invocation.getMethodName(), invocation.getParameterTypes());
return new RpcResult(method.invoke(target, invocation.getArguments()));
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
@Override
public URL getUrl() {
return url;
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public void destroy() {
}
}
创建一个动态代理类
package com.alibaba.dubbo.rpc.proxy;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcInvocation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* InvokerHandler
*/
public class InvokerInvocationHandler implements InvocationHandler {
// 真实对象为Invoker对象
private final Invoker<?> invoker;
public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
if (method.getDeclaringClass() == Object.class) {
return method.invoke(invoker, args);
}
if ("toString".equals(methodName) && parameterTypes.length == 0) {
return invoker.toString();
}
if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
return invoker.hashCode();
}
if ("equals".equals(methodName) && parameterTypes.length == 1) {
return invoker.equals(args[0]);
}
// 执行invoker方法
return invoker.invoke(new RpcInvocation(method, args)).recreate();
}
}
实现一个protocol类(rmi)
package com.enjoy.protocol;
import java.lang.reflect.Proxy;
import java.rmi.RemoteException;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.remoting.rmi.RmiProxyFactoryBean;
import org.springframework.remoting.rmi.RmiServiceExporter;
import org.springframework.remoting.support.RemoteInvocation;
import org.springframework.remoting.support.RemoteInvocationFactory;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.Version;
import com.alibaba.dubbo.rpc.Exporter;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Protocol;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.protocol.rmi.RmiRemoteInvocation;
import com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler;
/**
* RmiProtocol.
*/
public class RmiProtocol implements Protocol {
public static final int DEFAULT_PORT = 1099;
@Override
public int getDefaultPort() {
return DEFAULT_PORT;
}
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
// 创建spring rmi服务
final RmiServiceExporter rmiServiceExporter = new RmiServiceExporter();
rmiServiceExporter.setRegistryPort(invoker.getUrl().getPort());
rmiServiceExporter.setServiceName(invoker.getUrl().getPath());
rmiServiceExporter.setServiceInterface(invoker.getInterface());
// 此时目标服务没有,需要通过invoker调通,使用代理 创建一个动态代理
T service = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[] { invoker.getInterface() }, new InvokerInvocationHandler(invoker));
rmiServiceExporter.setService(service);// DemoService service,如果能拿它,直接设入就ok
try {
rmiServiceExporter.afterPropertiesSet();
} catch (RemoteException e) {
throw new RpcException(e.getMessage(), e);
}
return null;
}
@Override
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
T obj = doRefer(type, url);
return new SimpleInvoker(obj, type, url);
}
// 客户端
public <T> T doRefer(Class<T> type, URL url) throws RpcException {
final RmiProxyFactoryBean rmiProxyFactoryBean = new RmiProxyFactoryBean();
// 使用dubbo协议
if (url.getParameter(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion())
.equals(Version.getProtocolVersion())) {
rmiProxyFactoryBean.setRemoteInvocationFactory(new RemoteInvocationFactory() {
@Override
public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) {
return new RmiRemoteInvocation(methodInvocation);
}
});
}
rmiProxyFactoryBean.setServiceUrl(url.toIdentityString());
rmiProxyFactoryBean.setServiceInterface(type);
rmiProxyFactoryBean.setCacheStub(true);
rmiProxyFactoryBean.setLookupStubOnStartup(true);
rmiProxyFactoryBean.setRefreshStubOnConnectFailure(true);
rmiProxyFactoryBean.afterPropertiesSet();
// 使用spring rmi远程调用
return (T) rmiProxyFactoryBean.getObject();
}
@Override
public void destroy() {
}
}
调用逻辑
package com.enjoy;
import java.io.IOException;
import java.lang.reflect.Proxy;
import org.junit.Test;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Protocol;
import com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler;
import com.enjoy.protocol.RmiProtocol;
import com.enjoy.protocol.SimpleInvoker;
import com.enjoy.service.DemoService;
import com.enjoy.service.DemoServiceImpl;
public class RpcProtocolTest {
URL url = URL.valueOf("rmi://127.0.0.1:9001/"+ DemoService.class.getName());
/**
* 服务端 invoker->protocol
* Protocol连接服务端invoker
* 将目标服务调用信息,包装成为invoker实体,暴露到网络上
*
* 当网络信息到达,将触发invoker的invoke方法,最终将调用转到目标service上
*/
@Test
public void invoker2protocol() throws IOException {
DemoService service = new DemoServiceImpl();
// 将服务类包装到Invoker对象中
Invoker<DemoService> invoker = new SimpleInvoker(service,DemoService.class,url);
Protocol protocol = new RmiProtocol();
//暴露对象
protocol.export(invoker);
System.out.println("Dubbo server 启动");
// 保证服务一直开着
System.in.read();
}
/**
* Protocol连接消费端invoker
* 将要调用的信息,包装成invoker实体,向网络发送
*
* 本地调用接口代理时,最终方法被转到invoker的invoke方法上,向网络发送
*/
@Test
public void protocol2Invoker() {
//协议
Protocol protocol = new RmiProtocol();
//消费invoker,负责发送协议调用信息 也是创建一个Invoker
Invoker<DemoService> invoker = protocol.refer(DemoService.class, url);
//做一个动态代理,将调用目标指向invoker即可
DemoService service = (DemoService)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{invoker.getInterface()},
new InvokerInvocationHandler(invoker));//反射逻辑
// 上面只是生成了一个代理,实际执行方法时才会真实调用,触发invoker
String result = service.sayHello("peter");
System.out.println(result);
}
}