您现在的位置是:主页 > news > php做音乐网站/最能打动顾客的十句话
php做音乐网站/最能打动顾客的十句话
admin2025/6/21 20:35:57【news】
简介php做音乐网站,最能打动顾客的十句话,淘宝联盟合作网站api,检察机关门户网站建设工作自查报告注:本文基于dubbo v2.6.x 1.ServiceConfig类 我们先来看看ServiceConfig类,ServiceConfig可以说是每暴露一个接口就会有一个ServiceConfig对象,比如说我现在有2个接口 然后有2个对应的实现类,那么我们在服务暴露的时候就会有2个…
注:本文基于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() {@Overridepublic 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()));// timestampif (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 typeif (argument.getType() != null && argument.getType().length() > 0) {Method[] methods = interfaceClass.getMethods();// visit all methodsif (methods != null && methods.length > 0) {for (int i = 0; i < methods.length; i++) {String methodName = methods[i].getName();// target the method, and get its signatureif (methodName.equals(method.getName())) {Class<?>[] argtypes = methods[i].getParameterTypes();// one callback in the methodif (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 methodfor (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())) {// 本地injvmprotocolConfig.setRegister(false);map.put("notify", "false");}// export serviceString contextPath = protocolConfig.getContextpath();if ((contextPath == null || contextPath.length() == 0) && provider != null) {contextPath = provider.getContextpath();}// hostString host = this.findConfigedHosts(protocolConfig, registryURLs, map);Integer port = this.findConfigedPorts(protocolConfig, name, map);// portURL 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 configuredif (!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)) { // 远程服务暴露 不是localif (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 invokerString proxy = url.getParameter(Constants.PROXY_KEY); // 配置中有proxy_key 的话就使用配置的if (StringUtils.isNotEmpty(proxy)) { // 设置配置的 proxy_keyregistryURL = 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);// 添加exporterexporters.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不是injvmif (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {// 设置protolol是injvmURL 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*/@Overridepublic <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*/@Overrideprotected 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*/@Overrideprotected 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 !=nullif (proxy == null) {throw new IllegalArgumentException("proxy == null");}//type !=nullif (type == null) {throw new IllegalArgumentException("interface == null");}// proxy 需要是实现typeif (!type.isInstance(proxy)) {throw new IllegalArgumentException(proxy.getClass().getName() + " not implement interface " + type);}this.proxy = proxy;this.type = type;this.url = url;}@Overridepublic Class<T> getInterface() {return type;}@Overridepublic URL getUrl() {return url;}@Overridepublic boolean isAvailable() {return true;}@Overridepublic void destroy() {}/*** 调用* @param invocation 调用实体* @return 结果实体* @throws RpcException*/@Overridepublic 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;@Overridepublic 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;}}@Overridepublic int getDefaultPort() {return DEFAULT_PORT;}/*** 服务暴露* @param invoker Service invoker* @param <T>* @return* @throws RpcException*/@Overridepublic <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 keyprivate 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);}@Overridepublic void unexport() {super.unexport();exporterMap.remove(key);}}
最终是将key=接口全类名,value=this(也就是InjvmExporter对象)put到exporterMap中了。
再回到ServiceConfig的exportLocal方法中。还有最后一句exporters.add(exporter);
这里是将上面生成的InjvmExporter对象缓存了起来。
到这里我们这个服务本地暴露(injvm)就解析完成了。