spring容器啟動(dòng)的最后一步,就是實(shí)例化Bean;從上一節(jié)我們看到,dubbo中的service在注冊(cè)到spring容器中時(shí)是一個(gè)ServiceBean,這個(gè)ServiceBean可以理解成一個(gè)適配器,避免了dubbo中的ServcieConfig和spring直接集成。
public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware {
private static final long serialVersionUID = 213195494150089726L;
private static transient ApplicationContext SPRING_CONTEXT;
private final transient Service service;
private transient ApplicationContext applicationContext;
private transient String beanName;
public void onApplicationEvent(ContextRefreshedEvent event) {
if (isDelay() && !isExported() && !isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
export();
}
}
/** spring容器在實(shí)例化Bean的過程中會(huì)調(diào)用這個(gè)方法 */
public void afterPropertiesSet() throws Exception {
...
// 前面一大段都先不看,都是用來確保service發(fā)布的環(huán)境已經(jīng)初始化好,后面再回過來細(xì)看,核心是下面這個(gè)export()方法
if (!isDelay()) {
export();
}
}
}
export方法在ServiceBean的父類ServiceConfig中,而在ServiceConfig中,又依次調(diào)用方法export() -> doExport() -> doExportUrls():
private void doExportUrls() {
List<URL> registryURLs = loadRegistries(true);
for (ProtocolConfig protocolConfig : protocols) {
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
從這個(gè)方法可以看出來,一個(gè)service是同時(shí)支持多個(gè)協(xié)議的,在Service類上的標(biāo)注可以這么寫:@Service(protocol = {"dubbo","rest"}),繼續(xù)往下看:
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
// 前面的一大段還是忽略,主要是為service的export提供參數(shù)的,包括所有的方法名稱、重試次數(shù)、接口版本號(hào)等
...
// 關(guān)鍵是這里,調(diào)用具體協(xié)議的export方法
Exporter<?> exporter = protocol.export(wrapperInvoker);
...
先看看Dubbo協(xié)議是怎么export Service的,進(jìn)入DubboProtocal類的export方法:
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
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 dispatching event
Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT);
Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
if (isStubSupportEvent && !isCallbackservice) {
String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
if (logger.isWarnEnabled()) {
logger.warn(new IllegalStateException("consumer [" + url.getParameter(Constants.INTERFACE_KEY) +
"], has set stubproxy support event ,but no stub methods founded."));
}
} else {
stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
}
}
// 主要看這個(gè)方法
openServer(url);
optimizeSerialization(url);
return exporter;
}
...
private ExchangeServer createServer(URL url) {
// send readonly event when server closes, it's enabled by default
url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString());
// enable heartbeat by default
url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER);
if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str))
throw new RpcException("Unsupported server type: " + str + ", url: " + url);
url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME);
ExchangeServer server;
try {
// 進(jìn)入交換層
server = Exchangers.bind(url, requestHandler);
} catch (RemotingException e) {
throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
}
str = url.getParameter(Constants.CLIENT_KEY);
if (str != null && str.length() > 0) {
Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
if (!supportedTypes.contains(str)) {
throw new RpcException("Unsupported client type: " + str);
}
}
return server;
}
dubbo協(xié)議使用的是默認(rèn)的HeaderExchanger:
/**
* DefaultMessenger
*
*
*/
public class HeaderExchanger implements Exchanger {
public static final String NAME = "header";
@Override
public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
return new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true);
}
@Override
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}
}
可以看到,在bind方法中通過調(diào)用Transport層的bind方法來創(chuàng)建ExchangerServer,來看看Transporters類的bind方法:
public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException {
if (url == null) {
throw new IllegalArgumentException("url == null");
}
if (handlers == null || handlers.length == 0) {
throw new IllegalArgumentException("handlers == null");
}
ChannelHandler handler;
if (handlers.length == 1) {
handler = handlers[0];
} else {
handler = new ChannelHandlerDispatcher(handlers);
}
return getTransporter().bind(url, handler);
}
由于dubbo協(xié)議默認(rèn)使用netty來進(jìn)行遠(yuǎn)程調(diào)用,我們看看NettyTransporter:
public class NettyTransporter implements Transporter {
public static final String NAME = "netty";
@Override
public Server bind(URL url, ChannelHandler listener) throws RemotingException {
return new NettyServer(url, listener);
}
@Override
public Client connect(URL url, ChannelHandler listener) throws RemotingException {
return new NettyClient(url, listener);
}
}
可以看到,最終就是啟動(dòng)了NettyServer。