版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhuqiuhui/article/details/83689385
-
dubbo标签解析
spring通过在DubboNamespaceHandler注册dubbo解析器DubboBeanDefinitionParser,在加载Bean的时候同时解析dubbo标签并加载dubbo标签解析后的Bean
-
暴露dubbo服务
dubbo标签解析完成后,会把dubbo:service标签解析解析成类型为ServiceBean的RootBeanDefinition,并进行实例化,
<!--定义了提供方应用信息,用于计算依赖关系;在 dubbo-admin 或 dubbo-monitor 会显示这个名字,方便辨识--> <dubbo:application name="debbo-provider" owner="programmer" organization="dubbox"/> <!--使用 zookeeper 注册中心暴露服务,注意要先开启 zookeeper--> <dubbo:registry address="zookeeper://localhost:2181"/> <!-- 用dubbo协议在20880端口暴露服务 --> <dubbo:protocol name="dubbo" port="20880" /> <!--使用 dubbo 协议实现定义好的 api.PermissionService 接口--> <dubbo:service interface="service.DemoService" ref="demoService" protocol="dubbo" /> <!--具体实现该接口的 bean--> <bean id="demoService" class="Impl.DemoServiceImpl"/>
由于ServiceBean实现了InitializingBean和ApplicationListener接口,一个是在类初始化完成后调用afterPropertiesSet方法,一个在Spring容器初始化完成后会调用onApplicationEvent方法(调用参考bean的加载过程),即重要的就是这两个方法,这两个方法
public void afterPropertiesSet() throws Exception { // ServiceConfig根据dubbo:provider标签设置provider // ServiceConfig根据dubbo:application标签设置应用信息配置 // SerivceConfig根据dubbo:module标签设置模块信息配置 // SerivceConfig设置注册中心 // SerivceConfig根据dubbo:monitor标签设置监控中心配置 // SerivceConfig设置服务提供者协议配置 if (! isDelay()) { export(); } } public void onApplicationEvent(ApplicationEvent event) { if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) { if (isDelay() && ! isExported() && ! isUnexported()) { export(); } } } public synchronized void export() { //省略代码,从provider中获取delay if (delay != null && delay > 0) { Thread thread = new Thread(new Runnable() { public void run() { // 睡delay时间 Thread.sleep(delay); // 暴露服务 doExport(); } }); thread.setDaemon(true); thread.setName("DelayExportServiceThread"); thread.start(); } else { // 没有设置delay,直接暴露服务 doExport(); } } protected synchronized void doExport() { // 省略大部分校验代码...... doExportUrls(); } private void doExportUrls() { List<URL> registryURLs = loadRegistries(true); // 按照不同的Protocol如(dubbo,injvm)来暴露服务 for (ProtocolConfig protocolConfig : protocols) { // 1.如果协议类型为null,则默认为dubbo协议 String name = protocolConfig.getName(); if (name == null || name.length() == 0) { name = "dubbo"; } // 2.获取主机名host(省略代码) // 3.获取端口号port(省略代码) // 4.参数设置到map中 Map<String, String> map = new HashMap<String, String>(); // URL中的side属性,有两个值,一个provider,一个consumer,暴露服务的时候为provider map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE); // dubbo的版本号 url中的dubbo map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion()); // url中的timestamp map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); //url中的pid if (ConfigUtils.getPid() > 0) { map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid())); } //从其他参数中获取参数 appendParameters(map, application); appendParameters(map, module); appendParameters(map, provider, Constants.DEFAULT_KEY); appendParameters(map, protocolConfig); appendParameters(map, this); // 从暴露的方法配置信息中获取参数和值(代码省略) // 通用服务接口和非通用服务接口的参数 if (generic) { // 通用服务接口 map.put("generic", String.valueOf(true)); map.put("methods", Constants.ANY_VALUE); } else { String revision = Version.getVersion(interfaceClass, version); if (revision != null && revision.length() > 0) { map.put("revision", revision); } map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(Wrapper.getWrapper(interfaceClass).getDeclaredMethodNames())), ",")); } //5.token 临牌校验(代码省略) //6.injvm协议处理(代码省略) //7.导出服务 // 获取上下文路径 String contextPath = protocolConfig.getContextpath(); if ((contextPath == null || contextPath.length() == 0) && provider != null) { contextPath = provider.getContextpath(); } // 组装URL URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map); // 如果url使用的协议存在扩展,调用对应的扩展来修改原url(代码省略) String scope = url.getParameter(Constants.SCOPE_KEY); //配置为none不暴露 if (! Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) { //配置不是remote的情况下做本地暴露 (配置为remote,则表示只暴露远程服务) if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) { exportLocal(url); } //如果配置不是local则暴露为远程服务.(配置为local,则表示只暴露本地服务) if (! Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope) ){ if (registryURLs != null && registryURLs.size() > 0 && url.getParameter("register", true)) { for (URL registryURL : registryURLs) { // 省略部分代码 // 通过代理工厂将ref对象转化成invoker对象 Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString())); // 暴露服务(DubboProtocol来暴露服务,) Exporter<?> exporter = protocol.export(invoker); //一个服务可能有多个提供者,保存在一起 exporters.add(exporter); } } else { Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url); Exporter<?> exporter = protocol.export(invoker); exporters.add(exporter); } } } this.urls.add(url); } }
注:<dubbo:reference…scope=“remote”/>,scope为remote表示引用远程服务;为local表示引用本地服务;
DubboProtocol中暴露服务:
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { // 获取URL URL url = invoker.getUrl(); // export service. String key = serviceKey(url); DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap); exporterMap.put(key, exporter); //export an stub service for dispaching event(代码省略) openServer(url); return exporter; } private void openServer(URL url) { // 查找服务 String key = url.getAddress(); //client 也可以暴露一个只有server可以调用的服务,所以需要判断是否是服务端 boolean isServer = url.getParameter(Constants.IS_SERVER_KEY,true); if (isServer) { ExchangeServer server = serverMap.get(key); if (server == null) { //如果服务不存在,创建服务 serverMap.put(key, getServer(url)); } else { //server支持reset,配合override功能使用 server.reset(url); } } } private ExchangeServer getServer(URL url) { // 忽略部分代码 ExchangeServer server; server = Exchangers.bind(url, requestHandler); return server; } // 上述最终会调用到Netty public class NettyTransporter implements Transporter { public static final String NAME = "netty"; public Server bind(URL url, ChannelHandler listener) throws RemotingException { return new NettyServer(url, listener); } // ...... }
我的修行之路,欢迎讨论!
微信:bboyzqh
邮箱:[email protected]