注:本文基于dubbo v2.6.x
1.ServiceConfig类
我们先来看看ServiceConfig类,ServiceConfig可以说是每暴露一个接口就会有一个ServiceConfig对象,比如说我现在有2个接口
然后有2个对应的实现类,那么我们在服务暴露的时候就会有2个ServiceConfig实例,其实我们看它的属性的时候也能猜到
我这里只是截了3个成员,第一个是接口名,第二个是接口的class对象,第三个就是接口的具体实现类。
接下来我们具体看看ServiceConfig的成员:
// 自适应Protocol ,这个就跟变色龙似的,能够根据具体的参数值变成不同的实现
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
//代理工厂的自适应
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
//记录随机端口的
private static final Map<String, Integer> RANDOM_PORT_MAP = new HashMap<String, Integer>();
// 延时暴露 executor
private static final ScheduledExecutorService delayExportExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true));
private final List<URL> urls = new ArrayList<URL>();
// exporters
private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>();
// interface type
private String interfaceName; // 接口名
private Class<?> interfaceClass;//接口class
// reference to interface impl
private T ref;// 具体实现类
// service name
private String path;
// method configuration
//方法的配置
private List<MethodConfig> methods;
// 关于provider的配置
private ProviderConfig provider;
// 是否已经暴露
private transient volatile boolean exported;
//是否需要暴露
private transient volatile boolean unexported;
//范化
private volatile String generic;
我对这个进行了中文标注,然后我们来看下具体的服务暴露方法export():
public synchronized void export() {
if (provider != null) {
if (export == null) {
export = provider.getExport();
}
if (delay == null) {
delay = provider.getDelay();
}
}
if (export != null && !export) {
return;
}
// 延时暴露
if (delay != null && delay > 0) {
delayExportExecutor.schedule(new Runnable() {
@Override
public void run() {
doExport();
}
}, delay, TimeUnit.MILLISECONDS);
} else {
doExport();
}
}
我们可以看到这个方法主要做的工作是服务暴露延迟的,如果delay不是null && delay>0 然后给ScheduledExecutorService然后 delay ms后再进行服务暴露,我们要想使用延迟暴露功能,可以在@Service注解中添加delay 属性。
@Service(delay =1000 )
也可以在xml中添加
<dubbo:provider delay="100"/>
<dubbo:service interface="xxx.xxx.xxx" delay="1000"></dubbo:service>
我们再接着往下看不延迟暴露走doExport()方法,
protected synchronized void doExport() {
if (unexported) {
throw new IllegalStateException("Already unexported!");
}
if (exported) {
return;
}
exported = true;
if (interfaceName == null || interfaceName.length() == 0) {
throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
}
checkDefault();
if (provider != null) {
if (application == null) {
application = provider.getApplication();
}
if (module == null) {
module = provider.getModule();
}
if (registries == null) {
registries = provider.getRegistries();
}
if (monitor == null) {
monitor = provider.getMonitor();
}
if (protocols == null) {
protocols = provider.getProtocols();
}
}
if (module != null) {
if (registries == null) {
registries = module.getRegistries();
}
if (monitor == null) {
monitor = module.getMonitor();
}
}
if (application != null) {
if (registries == null) {
registries = application.getRegistries();
}
if (monitor == null) {
monitor = application.getMonitor();
}
}
if (ref instanceof GenericService) {
interfaceClass = GenericService.class;
if (StringUtils.isEmpty(generic)) {
generic = Boolean.TRUE.toString();
}
} else {
try {// 创建class对象
interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}// 检查方法是否在接口中
checkInterfaceAndMethods(interfaceClass, methods);
checkRef();// 检查实现类
generic = Boolean.FALSE.toString();// 不是泛化
}
if (local != null) {
if ("true".equals(local)) {
local = interfaceName + "Local";
}
Class<?> localClass;
try {
localClass = ClassHelper.forNameWithThreadContextClassLoader(local);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
if (!interfaceClass.isAssignableFrom(localClass)) {
throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);
}
}
if (stub != null) {
if ("true".equals(stub)) {
stub = interfaceName + "Stub";
}
Class<?> stubClass;
try {
stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
if (!interfaceClass.isAssignableFrom(stubClass)) {
throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
}
}
checkApplication();
checkRegistry();
checkProtocol();
appendProperties(this);
checkStub(interfaceClass);
checkMock(interfaceClass);
if (path == null || path.length() == 0) {
path = interfaceName;
}
doExportUrls();
ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);
ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
}
前几行就是判断服务是否暴露,然后把exported 属性设置成true。判断接口名interfaceName不是空。接着就是 checkDefault();checkDefault主要就是检查provider是否是null,是null就创建,然后设置一些属性到provider中。
接着就是把provider中的application,module,registries,monitor,protocols赋值给SerivceConfig属性。
接着就是判断 接口类型是否是GenericService ,其实这个GenericService接口是范化接口,然后把 interfaceClass 设置成GenericService的class , generic = Boolean.TRUE.toString();
如果不是范化,创建interfaceClass,检查方法是否在接口中,接着是检查实现类是否是接口的实现类。generic = Boolean.FALSE.toString(); 设置不是范化。后面的都是一些检查配置参数的。
接着就是doExportUrls方法:
@SuppressWarnings({"unchecked", "rawtypes"})
private void doExportUrls() {
List<URL> registryURLs = loadRegistries(true);
for (ProtocolConfig protocolConfig : protocols) {
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
我们可以看到先走了loadRegistries(true); 这个方法,获取到了一个URL集合,其实这里就是获取注册中心列表,一个URL就是一个注册中心
我们可以看下
接着就是循环暴露doExportUrlsFor1Protocol(protocolConfig, registryURLs);
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
String name = protocolConfig.getName();
if (name == null || name.length() == 0) {
name = "dubbo";/// 默认是dubbo
}
Map<String, String> map = new HashMap<String, String>();
map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);// side 哪一端
map.put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion());// 版本
map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));// timestamp
if (ConfigUtils.getPid() > 0) {
map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));// pid
}
appendParameters(map, application);
appendParameters(map, module);
appendParameters(map, provider, Constants.DEFAULT_KEY);
appendParameters(map, protocolConfig);
appendParameters(map, this);
if (methods != null && !methods.isEmpty()) {
for (MethodConfig method : methods) {
appendParameters(map, method, method.getName());
String retryKey = method.getName() + ".retry";
if (map.containsKey(retryKey)) {
String retryValue = map.remove(retryKey);
if ("false".equals(retryValue)) {
map.put(method.getName() + ".retries", "0");
}
}
List<ArgumentConfig> arguments = method.getArguments();
if (arguments != null && !arguments.isEmpty()) {
for (ArgumentConfig argument : arguments) {
// convert argument type
if (argument.getType() != null && argument.getType().length() > 0) {
Method[] methods = interfaceClass.getMethods();
// visit all methods
if (methods != null && methods.length > 0) {
for (int i = 0; i < methods.length; i++) {
String methodName = methods[i].getName();
// target the method, and get its signature
if (methodName.equals(method.getName())) {
Class<?>[] argtypes = methods[i].getParameterTypes();
// one callback in the method
if (argument.getIndex() != -1) {
if (argtypes[argument.getIndex()].getName().equals(argument.getType())) {
appendParameters(map, argument, method.getName() + "." + argument.getIndex());
} else {
throw new IllegalArgumentException("argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
}
} else {
// multiple callbacks in the method
for (int j = 0; j < argtypes.length; j++) {
Class<?> argclazz = argtypes[j];
if (argclazz.getName().equals(argument.getType())) {
appendParameters(map, argument, method.getName() + "." + j);
if (argument.getIndex() != -1 && argument.getIndex() != j) {
throw new IllegalArgumentException("argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
}
}
}
}
}
}
}
} else if (argument.getIndex() != -1) {
appendParameters(map, argument, method.getName() + "." + argument.getIndex());
} else {
throw new IllegalArgumentException("argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
}
}
}
} // end of methods for
}
if (ProtocolUtils.isGeneric(generic)) {//泛化调用
map.put(Constants.GENERIC_KEY, generic);
map.put(Constants.METHODS_KEY, Constants.ANY_VALUE);
} else {
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
map.put("revision", revision);
}
String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
if (methods.length == 0) {
logger.warn("NO method found in service interface " + interfaceClass.getName());
map.put(Constants.METHODS_KEY, Constants.ANY_VALUE);
} else {
map.put(Constants.METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
}
}
if (!ConfigUtils.isEmpty(token)) {
if (ConfigUtils.isDefault(token)) {
map.put(Constants.TOKEN_KEY, UUID.randomUUID().toString());
} else {
map.put(Constants.TOKEN_KEY, token);
}
}
if (Constants.LOCAL_PROTOCOL.equals(protocolConfig.getName())) {// 本地injvm
protocolConfig.setRegister(false);
map.put("notify", "false");
}
// export service
String contextPath = protocolConfig.getContextpath();
if ((contextPath == null || contextPath.length() == 0) && provider != null) {
contextPath = provider.getContextpath();
}
// host
String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
Integer port = this.findConfigedPorts(protocolConfig, name, map);// port
URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.hasExtension(url.getProtocol())) {
url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.getExtension(url.getProtocol()).getConfigurator(url).configure(url);
}
String scope = url.getParameter(Constants.SCOPE_KEY);
// don't export when none is configured
if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {
// export to local if the config is not remote (export to remote only when config is remote)
if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) { // 本地服务暴露 不是remote就本地暴露,如果不配置scope也进行本地暴露
exportLocal(url);
}
// export to remote if the config is not local (export to local only when config is local)
if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) { // 远程服务暴露 不是local
if (logger.isInfoEnabled()) {
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
}
if (registryURLs != null && !registryURLs.isEmpty()) {
//遍历注册中心
for (URL registryURL : registryURLs) {
url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));
URL monitorUrl = loadMonitor(registryURL);//获取监控中心
if (monitorUrl != null) { // 将监控中心添加到 url中
url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
}
// For providers, this is used to enable custom proxy to generate invoker
String proxy = url.getParameter(Constants.PROXY_KEY); // 配置中有proxy_key 的话就使用配置的
if (StringUtils.isNotEmpty(proxy)) { // 设置配置的 proxy_key
registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy);
}
// invoker 使用ProxyFactory 生成 invoker对象,这里这个invoker其实是一个代理对象
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
// 创建 DelegateProvoderMetaInvoker 对象
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
// registryURL.getProtocol= registry
// filter ---->listener --->registryProtocol ( 这里使用了wapper 包装机制)
// filter ----> listener ----> dubboProtocol 服务暴露
Exporter<?> exporter = protocol.export(wrapperInvoker);
// 添加exporter
exporters.add(exporter);
}
} else { // 没有注册中心
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
}
}
this.urls.add(url);
}
这个方法首先判断ProtocolConfig的协议,如果没有默认设置成dubbo,再往下就是设置参数,比如说side=provider,dubbo=2.2.0,timestamp,pid等等,然后把一些config中的配置塞到map中,接着就是遍历处理MethodConfig。再接着就是判断是不是范化调用,如果是就把范化的信息扔到map中,设置methods=*,如果不是范化调用,就找到你所有的method,然后将methods=你所有method名拼接起来。
接着就是将token参数塞到map中。如果你得协议是injvm,设置notify=false,protocolConfig.setRegister(false);
获取host,port,最终利用map里面这一堆配置创建出一个新的URL。
其实上面这些就是提取配置,封装配置,最后创建URL。
接着 String scope = url.getParameter(Constants.SCOPE_KEY); 获取配置的scope,如果你这个scope不是none,remote,这时候就会本地暴露,只要你没有显示的配置scope=remote,就会进行本地暴露,接下来我们就看下exportLocal(url)这个方法。
@SuppressWarnings({"unchecked", "rawtypes"})
private void exportLocal(URL url) { // 本地服务暴露
// 如果protocol不是injvm
if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
// 设置protolol是injvm
URL local = URL.valueOf(url.toFullString())
.setProtocol(Constants.LOCAL_PROTOCOL)
.setHost(LOCALHOST) // host 是127.0.0.1
.setPort(0);
//service.classimpl
StaticContext.getContext(Constants.SERVICE_IMPL_CLASS).put(url.getServiceKey(), getServiceClass(ref));
/**
* ref: 接口实现类
* interfaceClass: 接口class
* local : URL
*/
Exporter<?> exporter = protocol.export(
proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
exporters.add(exporter);
logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
}
}
首先是判断protocol不是injvm的话,就把URL中的protocol变成injvm,host是127.0.0.1,port是0 。其实这里是新生成了一个URL,把之前URL里面的配置搬过来了。接着就是往context中添加一个键值,key是接口的全类名,value是实现类的全类名。
再接着就是
Exporter<?> exporter = protocol.export(
proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
我们先来看下proxyFactory.getInvoker(ref, (Class) interfaceClass, local)这个方法。
proxyFactory是我们一个类成员
ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
获取了一个自适应的扩展实现类。我们看下这个自适应是根据哪个key来找实现类的。
@SPI("javassist")
public interface ProxyFactory {
/**
* create proxy.
*
* @param invoker
* @return proxy
*/
@Adaptive({Constants.PROXY_KEY})
<T> T getProxy(Invoker<T> invoker) throws RpcException;
/**
* create proxy.
*
* @param invoker
* @return proxy
*/
@Adaptive({Constants.PROXY_KEY})
<T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException;
/**
* create invoker.
*
* @param <T>
* @param proxy
* @param type
* @param url
* @return invoker
*/
@Adaptive({Constants.PROXY_KEY})
<T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}
咱们用的getInvoker方法,然后会根据proxy这个属性去咱们的URL中找对应的值,我们现在没有刻意设置这个proxy属性的话,就会走默认,也就是@SPI(“javassist”)中的javassist实现类。这块知识数据dubbo spi里面的。
我们来看看javassist实现类,也就是JavassistProxyFactory这个类。
/**
* JavaassistRpcProxyFactory
*/
public class JavassistProxyFactory extends AbstractProxyFactory {
@Override
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
//生成一个invoker的包装类
/**
* @param proxy 接口实现类
* @param type 接口类型class
* @param url URL
* @param <T> 接口类型
* @return Invoker
*/
@Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper cannot handle this scenario correctly: the classname contains '$' wrapper 不能解析类名中带$的
// 这里是如果,接口实现类中有$符号,就是用接口类型,没有$符号,就用实现类的类型
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(proxy, type, url) {
/**
* 进行调用
* @param proxy 实现类
* @param methodName 方法名
* @param parameterTypes 参数类型们
* @param arguments 参数
* @return
* @throws Throwable
*/
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
}
首先第一行,Wrapper.getWrapper,这个会帮你生成一个Wrapper,其实这个Wrapper会根据你提供的这个类型生成一个获取你这个类中成员变量的方法,设置成员变量的方法,执行你这个类中方法的方法。
我们可以来看下生成的啥样子
public class Wrapper$1 {
public static String[] pns;// 字段名
public static Map pts;//<字段名,字段类型>
public static String[] mns;//方法名
public static String[] dmns;//自己方法的名字
public static Class[] mts;//方法参数类型
public String[] getPropertyNames(){ return pns; }
public boolean hasProperty(String n){ return pts.containsKey(n); }
public Class getPropertyType(String n){ return (Class)pts.get(n); }
public String[] getMethodNames(){ return mns; }
public String[] getDeclaredMethodNames(){ return dmns; }
public void setPropertyValue(Object o, String n, Object v){
com.xuzhaocai.dubbo.provider.IHelloProviderService w;
try{
w = (( com.xuzhaocai.dubbo.provider.IHelloProviderService)$1);
}catch(Throwable e) {
throw new IllegalArgumentException(e);
}
if( $2.equals("字段名")){
w."字段名"= $3;
return ;
}
}
public Object getPropertyValue(Object o, String n){
com.xuzhaocai.dubbo.provider.IHelloProviderService w;
try{
w = (( com.xuzhaocai.dubbo.provider.IHelloProviderService)$1);
}catch(Throwable e){
throw new IllegalArgumentException(e);
}
if( $2.equals("字段名")){
return ($w) w."字段名";
}
return null;
}
public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws InvocationTargetException{
com.xuzhaocai.dubbo.provider.IHelloProviderService w;
try{
w = (( com.xuzhaocai.dubbo.provider.IHelloProviderService)$1);
}catch(Throwable e){
throw new IllegalArgumentException(e);
}
try{
if("方法名".equals($2) && 方法参数个数 == $3.length && $3[1].getName().equals("方法第几个参数的name")){
w.方法名(参数);
}
if("方法名".equals($2) && 方法参数个数 == $3.length && $3[1].getName().equals("方法第几个参数的name")){
w.方法名(参数);
}
} catch(Throwable e) {
throw new java.lang.reflect.InvocationTargetException(e);
}
throw new NoSuchMethodException("Not found method "+$2+" in class 你传进来那个实现类");
}
}
就是针对你这个类生成了3个方法,setPropertyValue(Object o, String n, Object v)
往o中设置属性
,Object getPropertyValue(Object o, String n)
从o中取属性值
,
Object invokeMethod(Object o, String n, Class[] p, Object[] v)
执行o的某个方法。
我们接着往下看:
return new AbstractProxyInvoker<T>(proxy, type, url) {
/**
* 进行调用
* @param proxy 实现类
* @param methodName 方法名
* @param parameterTypes 参数类型们
* @param arguments 参数
* @return
* @throws Throwable
*/
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
我们来看下这个AbstractProxyInvoker这个抽象类。
/**
* InvokerWrapper
*/
public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
private final T proxy;
private final Class<T> type;
private final URL url;
public AbstractProxyInvoker(T proxy, Class<T> type, URL url) {
// 参数验证 proxy !=null
if (proxy == null) {
throw new IllegalArgumentException("proxy == null");
}
//type !=null
if (type == null) {
throw new IllegalArgumentException("interface == null");
}
// proxy 需要是实现type
if (!type.isInstance(proxy)) {
throw new IllegalArgumentException(proxy.getClass().getName() + " not implement interface " + type);
}
this.proxy = proxy;
this.type = type;
this.url = url;
}
@Override
public Class<T> getInterface() {
return type;
}
@Override
public URL getUrl() {
return url;
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public void destroy() {
}
/**
* 调用
* @param invocation 调用实体
* @return 结果实体
* @throws RpcException
*/
@Override
public Result invoke(Invocation invocation) throws RpcException {
try {
return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()));
} catch (InvocationTargetException e) {
return new RpcResult(e.getTargetException());
} catch (Throwable e) {
throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
//实际调用子类实现
protected abstract Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;
@Override
public String toString() {
return getInterface() + " -> " + (getUrl() == null ? " " : getUrl().toString());
}
}
可以看出AbstractProxyInvoker这个抽象类非常简单,构造中对T proxy 接口实现类,具体提供服务, Class type 接口类型, URL url ,这三个参数进行检验,然后存储。
实现接口Invoker的invoke(Invocation invocation)方法,实际上还是子类实现doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) 方法。
现在再看JavassistProxyFactory类就清楚了,最终走的是wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
上面这部分是proxyFactory.getInvoker(ref, (Class) interfaceClass, local)
,接着我们看下
protocol.export();
protocol.export(
proxyFactory.getInvoker(ref, (Class) interfaceClass, local)
);
这里这个protocol也是ServiceConfig的类成员,获取自适应实现类。我们看下Protocol接口
@SPI("dubbo")
public interface Protocol {
int getDefaultPort();
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
@Adaptive
<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
void destroy();
}
因为我们URL这里protocol=injvm,所以回去找对应的实现,也就是InjvmProtocol这个类。
/**
* InjvmProtocol
*/
public class InjvmProtocol extends AbstractProtocol implements Protocol {
public static final String NAME = Constants.LOCAL_PROTOCOL;
public static final int DEFAULT_PORT = 0;
private static InjvmProtocol INSTANCE;
public InjvmProtocol() {
INSTANCE = this;
}
public static InjvmProtocol getInjvmProtocol() {
if (INSTANCE == null) {
ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(InjvmProtocol.NAME); // load
}
return INSTANCE;
}
static Exporter<?> getExporter(Map<String, Exporter<?>> map, URL key) {
Exporter<?> result = null;
if (!key.getServiceKey().contains("*")) {
result = map.get(key.getServiceKey());
} else {
if (map != null && !map.isEmpty()) {
for (Exporter<?> exporter : map.values()) {
if (UrlUtils.isServiceKeyMatch(key, exporter.getInvoker().getUrl())) {
result = exporter;
break;
}
}
}
}
if (result == null) {
return null;
} else if (ProtocolUtils.isGeneric(
result.getInvoker().getUrl().getParameter(Constants.GENERIC_KEY))) {
return null;
} else {
return result;
}
}
@Override
public int getDefaultPort() {
return DEFAULT_PORT;
}
/**
* 服务暴露
* @param invoker Service invoker
* @param <T>
* @return
* @throws RpcException
*/
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
}
...
我把这次无关的方法先去掉了,看下 export方法,然后new InjvmExporter类
/**
* InjvmExporter
*/
class InjvmExporter<T> extends AbstractExporter<T> {
//service key
private final String key;
private final Map<String, Exporter<?>> exporterMap;
InjvmExporter(Invoker<T> invoker, String key, Map<String, Exporter<?>> exporterMap) {
super(invoker);
this.key = key;
this.exporterMap = exporterMap;
exporterMap.put(key, this);
}
@Override
public void unexport() {
super.unexport();
exporterMap.remove(key);
}
}
最终是将key=接口全类名,value=this(也就是InjvmExporter对象)put到exporterMap中了。
再回到ServiceConfig的exportLocal方法中。还有最后一句exporters.add(exporter);
这里是将上面生成的InjvmExporter对象缓存了起来。
到这里我们这个服务本地暴露(injvm)就解析完成了。