Springboot 中整合 RSocketPortInfoApplicationContextInitializer

源码分析:

private static class Listener implements ApplicationListener<RSocketServerInitializedEvent> {

		private static final String PROPERTY_NAME = "local.rsocket.server.port";

		private final ConfigurableApplicationContext applicationContext;

		Listener(ConfigurableApplicationContext applicationContext) {
			this.applicationContext = applicationContext;
		}

		@Override
		public void onApplicationEvent(RSocketServerInitializedEvent event) {
			if (event.getServer().address() != null) {
				setPortProperty(this.applicationContext, event.getServer().address().getPort());
			}
		}

		private void setPortProperty(ApplicationContext context, int port) {
			if (context instanceof ConfigurableApplicationContext configurableContext) {
				setPortProperty(configurableContext.getEnvironment(), port);
			}
			if (context.getParent() != null) {
				setPortProperty(context.getParent(), port);
			}
		}

		private void setPortProperty(ConfigurableEnvironment environment, int port) {
			MutablePropertySources sources = environment.getPropertySources();
			PropertySource<?> source = sources.get("server.ports");
			if (source == null) {
				source = new MapPropertySource("server.ports", new HashMap<>());
				sources.addFirst(source);
			}
			setPortProperty(port, source);
		}

		@SuppressWarnings("unchecked")
		private void setPortProperty(int port, PropertySource<?> source) {
			((Map<String, Object>) source.getSource()).put(PROPERTY_NAME, port);
		}

	}

RSocketServerBootstrap.java

public class RSocketServerBootstrap implements ApplicationEventPublisherAware, SmartLifecycle {

	private final RSocketServer server;

	private ApplicationEventPublisher eventPublisher;

	public RSocketServerBootstrap(RSocketServerFactory serverFactory, SocketAcceptor socketAcceptor) {
		Assert.notNull(serverFactory, "ServerFactory must not be null");
		this.server = serverFactory.create(socketAcceptor);
	}

	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
		this.eventPublisher = applicationEventPublisher;
	}

	@Override
	public void start() {
		this.server.start();
		this.eventPublisher.publishEvent(new RSocketServerInitializedEvent(this.server));
	}

	@Override
	public void stop() {
		this.server.stop();
	}

	@Override
	public boolean isRunning() {
		RSocketServer server = this.server;
		if (server != null) {
			return server.address() != null;
		}
		return false;
	}

}

源码分析:

public class RSocketServerInitializedEvent extends ApplicationEvent {

	public RSocketServerInitializedEvent(RSocketServer server) {
		super(server);
	}

	/**
	 * Access the {@link RSocketServer}.
	 * @return the embedded RSocket server
	 */
	public RSocketServer getServer() {
		return getSource();
	}

	/**
	 * Access the source of the event (an {@link RSocketServer}).
	 * @return the embedded web server
	 */
	@Override
	public RSocketServer getSource() {
		return (RSocketServer) super.getSource();
	}

}

message 中考虑:

@FunctionalInterface
public interface RSocketStrategiesCustomizer {

	/**
	 * Callback to customize a {@link RSocketStrategies#builder()} instance.
	 * @param strategies rSocket codec strategies to customize
	 */
	void customize(RSocketStrategies.Builder strategies);

}

netty server:

public class NettyRSocketServer implements RSocketServer {

	private static final Log logger = LogFactory.getLog(NettyRSocketServer.class);

	private final Mono<CloseableChannel> starter;

	private final Duration lifecycleTimeout;

	private CloseableChannel channel;

	public NettyRSocketServer(Mono<CloseableChannel> starter, Duration lifecycleTimeout) {
		Assert.notNull(starter, "starter must not be null");
		this.starter = starter;
		this.lifecycleTimeout = lifecycleTimeout;
	}

	@Override
	public InetSocketAddress address() {
		if (this.channel != null) {
			return this.channel.address();
		}
		return null;
	}

	@Override
	public void start() throws RSocketServerException {
		this.channel = block(this.starter, this.lifecycleTimeout);
		logger.info("Netty RSocket started on port(s): " + address().getPort());
		startDaemonAwaitThread(this.channel);
	}

	private void startDaemonAwaitThread(CloseableChannel channel) {
		Thread awaitThread = new Thread(() -> channel.onClose().block(), "rsocket");
		awaitThread.setContextClassLoader(getClass().getClassLoader());
		awaitThread.setDaemon(false);
		awaitThread.start();
	}

	@Override
	public void stop() throws RSocketServerException {
		if (this.channel != null) {
			this.channel.dispose();
			this.channel = null;
		}
	}

	private <T> T block(Mono<T> mono, Duration timeout) {
		return (timeout != null) ? mono.block(timeout) : mono.block();
	}

}

NettyRSocketServerFactory方法:

public class NettyRSocketServerFactory implements RSocketServerFactory, ConfigurableRSocketServerFactory {

	private int port = 9898;

	private DataSize fragmentSize;

	private InetAddress address;

	private RSocketServer.Transport transport = RSocketServer.Transport.TCP;

	private ReactorResourceFactory resourceFactory;

	private Duration lifecycleTimeout;

	private List<RSocketServerCustomizer> rSocketServerCustomizers = new ArrayList<>();

	private Ssl ssl;

	private SslStoreProvider sslStoreProvider;

	@Override
	public void setPort(int port) {
		this.port = port;
	}

	@Override
	public void setFragmentSize(DataSize fragmentSize) {
		this.fragmentSize = fragmentSize;
	}

	@Override
	public void setAddress(InetAddress address) {
		this.address = address;
	}

	@Override
	public void setTransport(RSocketServer.Transport transport) {
		this.transport = transport;
	}

	@Override
	public void setSsl(Ssl ssl) {
		this.ssl = ssl;
	}

	@Override
	public void setSslStoreProvider(SslStoreProvider sslStoreProvider) {
		this.sslStoreProvider = sslStoreProvider;
	}

	/**
	 * Set the {@link ReactorResourceFactory} to get the shared resources from.
	 * @param resourceFactory the server resources
	 */
	public void setResourceFactory(ReactorResourceFactory resourceFactory) {
		this.resourceFactory = resourceFactory;
	}

	/**
	 * Set {@link RSocketServerCustomizer}s that should be called to configure the
	 * {@link io.rsocket.core.RSocketServer} while building the server. Calling this
	 * method will replace any existing customizers.
	 * @param rSocketServerCustomizers customizers to apply before the server starts
	 * @since 2.2.7
	 */
	public void setRSocketServerCustomizers(Collection<? extends RSocketServerCustomizer> rSocketServerCustomizers) {
		Assert.notNull(rSocketServerCustomizers, "RSocketServerCustomizers must not be null");
		this.rSocketServerCustomizers = new ArrayList<>(rSocketServerCustomizers);
	}

	/**
	 * Add {@link RSocketServerCustomizer}s that should be called to configure the
	 * {@link io.rsocket.core.RSocketServer}.
	 * @param rSocketServerCustomizers customizers to apply before the server starts
	 * @since 2.2.7
	 */
	public void addRSocketServerCustomizers(RSocketServerCustomizer... rSocketServerCustomizers) {
		Assert.notNull(rSocketServerCustomizers, "RSocketServerCustomizers must not be null");
		this.rSocketServerCustomizers.addAll(Arrays.asList(rSocketServerCustomizers));
	}

	/**
	 * Set the maximum amount of time that should be waited when starting or stopping the
	 * server.
	 * @param lifecycleTimeout the lifecycle timeout
	 */
	public void setLifecycleTimeout(Duration lifecycleTimeout) {
		this.lifecycleTimeout = lifecycleTimeout;
	}

	@Override
	public NettyRSocketServer create(SocketAcceptor socketAcceptor) {
		ServerTransport<CloseableChannel> transport = createTransport();
		io.rsocket.core.RSocketServer server = io.rsocket.core.RSocketServer.create(socketAcceptor);
		configureServer(server);
		Mono<CloseableChannel> starter = server.bind(transport);
		return new NettyRSocketServer(starter, this.lifecycleTimeout);
	}

	private void configureServer(io.rsocket.core.RSocketServer server) {
		PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
		map.from(this.fragmentSize).asInt(DataSize::toBytes).to(server::fragment);
		this.rSocketServerCustomizers.forEach((customizer) -> customizer.customize(server));
	}

	private ServerTransport<CloseableChannel> createTransport() {
		if (this.transport == RSocketServer.Transport.WEBSOCKET) {
			return createWebSocketTransport();
		}
		return createTcpTransport();
	}

	private ServerTransport<CloseableChannel> createWebSocketTransport() {
		HttpServer httpServer = HttpServer.create();
		if (this.resourceFactory != null) {
			httpServer = httpServer.runOn(this.resourceFactory.getLoopResources());
		}
		if (this.ssl != null && this.ssl.isEnabled()) {
			httpServer = customizeSslConfiguration(httpServer);
		}
		return WebsocketServerTransport.create(httpServer.bindAddress(this::getListenAddress));
	}

	@SuppressWarnings("deprecation")
	private HttpServer customizeSslConfiguration(HttpServer httpServer) {
		org.springframework.boot.web.embedded.netty.SslServerCustomizer sslServerCustomizer = new org.springframework.boot.web.embedded.netty.SslServerCustomizer(
				this.ssl, null, getOrCreateSslStoreProvider());
		return sslServerCustomizer.apply(httpServer);
	}

	private ServerTransport<CloseableChannel> createTcpTransport() {
		TcpServer tcpServer = TcpServer.create();
		if (this.resourceFactory != null) {
			tcpServer = tcpServer.runOn(this.resourceFactory.getLoopResources());
		}
		if (this.ssl != null && this.ssl.isEnabled()) {
			TcpSslServerCustomizer sslServerCustomizer = new TcpSslServerCustomizer(this.ssl,
					getOrCreateSslStoreProvider());
			tcpServer = sslServerCustomizer.apply(tcpServer);
		}
		return TcpServerTransport.create(tcpServer.bindAddress(this::getListenAddress));
	}

	private SslStoreProvider getOrCreateSslStoreProvider() {
		if (this.sslStoreProvider != null) {
			return this.sslStoreProvider;
		}
		return CertificateFileSslStoreProvider.from(this.ssl);
	}

	private InetSocketAddress getListenAddress() {
		if (this.address != null) {
			return new InetSocketAddress(this.address.getHostAddress(), this.port);
		}
		return new InetSocketAddress(this.port);
	}

	@SuppressWarnings("deprecation")
	private static final class TcpSslServerCustomizer
			extends org.springframework.boot.web.embedded.netty.SslServerCustomizer {

		private TcpSslServerCustomizer(Ssl ssl, SslStoreProvider sslStoreProvider) {
			super(ssl, null, sslStoreProvider);
		}

		private TcpServer apply(TcpServer server) {
			AbstractProtocolSslContextSpec<?> sslContextSpec = createSslContextSpec();
			return server.secure((spec) -> spec.sslContext(sslContextSpec));
		}

	}

}

Rsocket 方法:

@FunctionalInterface
public interface RSocketServerCustomizer {

	/**
	 * Callback to customize a {@link RSocketServer} instance.
	 * @param rSocketServer the RSocket server to customize
	 */
	void customize(RSocketServer rSocketServer);

}

Rscoket:

@FunctionalInterface
public interface RSocketServerFactory {

	/**
	 * Gets a new fully configured but paused {@link RSocketServer} instance. Clients
	 * should not be able to connect to the returned server until
	 * {@link RSocketServer#start()} is called (which happens when the
	 * {@code ApplicationContext} has been fully refreshed).
	 * @param socketAcceptor the socket acceptor
	 * @return a fully configured and started {@link RSocketServer}
	 * @see RSocketServer#stop()
	 */
	RSocketServer create(SocketAcceptor socketAcceptor);

}

RSocket应用层协议支持 Reactive Streams语义, 例如:用RSocket作为HTTP的一种替代方案。
让我们从添加spring-boot-starter-rsocket依赖开始:

首先,我们设置由springboot应用程序引导的RSocket server服务器。 因为有spring-boot-starter-rsocket dependency依赖,所以springboot会自动配置RSocket server。 跟平常一样, 可以用属性驱动的方式修改RSocket server默认配置值。例如:通过增加如下配置在application.properties中,来修改RSocket端口:
这儿我们正在创建RSocket客户端并且配置TCP端口为:7000。注意: 该服务端口我们在前面已经配置过。 接下来我们定义了一个RSocket的装饰器对象RSocketRequester。 这个对象在我们跟RSocket server交互时会为我们提供帮助。 定义这些对象配置后,我们还只是有了一个骨架。在接下来,我们将暴露不同的交互模式, 并看看springboot在这个地方提供帮助的。

在服务器这边,我们首先应该创建一个controller 来持有我们的处理器方法。 我们会使用 @MessageMapping注解来代替像SpringMVC中的@RequestMapping或者@GetMapping注解

教你如何在Spring Boot中使用RSocket

来研究下我们的控制器。 我们将使用@Controller注解来定义一个控制器来处理进入RSocket的请求。 另外,注解@MessageMapping让我们定义我们感兴趣的路由和如何响应一个请求。 在这个示例中, 服务器监听路由currentMarketData, 并响应一个单一的结果Mono给客户端。
6.Spring Boot RSocket中的Request Stream
请求流是一种更复杂的交互模式, 这个模式中客户端发送一个请求,但是在一段时间内从服务器端获取到多个响应。 为了模拟这种交互模式, 客户端会询问给定股票的所有市场数据。

这里我们给异常处理方法标记注解为@MessageExceptionHandler。作为结果, 这个方法将处理所有类型的异常, 因为Exception是所有其他类型的异常的超类。 我们也可以明确地创建更多的不同类型的,不同的异常处理方法。 这当然是请求/响应模式,并且我们返回的是Mono。我们期望这里的响应类型跟我们的交互模式的返回类型相匹配。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值