ExecutorSubscribableChannel类,通过继承父类方法或直接声明,可以看作由 六
部分构成
ChannelInterceptor与ExecutorChannelInterceptor到底有什么区别,并如何工作?
ExecutorSubscribableChannel:
public
class
ExecutorSubscribableChannel
extends
AbstractSubscribableChannel
{
private
String beanName;
private
final
Set<
MessageHandler
> handlers = new
CopyOnWriteArraySet
<>();
private
final
Executor executor;
private
final
List<
ChannelInterceptor
> interceptors = new
ArrayList
<>(5);
private
final
List<
ExecutorChannelInterceptor
> executorInterceptors = new
ArrayList
<>(4);
/**
*
Invoke
a
MessageHandler
with
ExecutorChannelInterceptors
.
*/
private
class
SendTask
implements
MessageHandlingRunnable
{
}
}
在启用STOMP的时候——@EnableWebSocketMessageBroker,Spring框架会自动构造三个ExecutorSubscribableChannel实例:
工作方式如下图所示:
启用简单的消息代理:config.enableSimpleBroker
启用STOMP代理中继:config.enableStompBrokerRelay
WebSocketMessageBrokerConfigurer实现类:
@Configuration
@EnableWebSocketMessageBroker
public
class
WebSocketConfigurer
implements
WebSocketMessageBrokerConfigurer
{
@Override
public
void
configureMessageBroker
(MessageBrokerRegistry config) {
config.
configureBrokerChannel
().
taskExecutor
();
}
@Override
public
void
configureClientInboundChannel
(ChannelRegistration registration) {
}
@Override
public
void
configureClientOutboundChannel
(ChannelRegistration registration) {
}
}
EnableWebSocketMessageBroker:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebSocketMessageBrokerConfiguration.
class
)
public
@
interface
EnableWebSocketMessageBroker
{
}
一个相关成员变量
和四个相关方法
:
WebSocketMessageBrokerConfigurer
提供的自定义配置信息。clientInboundChannelExecutor()
获得Executor实例,通过getClientInboundChannelRegistration()
获得通道的其他配置信息,用来构造一个ExecutorSubscribableChannel
实例做为“clientInboundChannel”;getClientInboundChannelRegistration()
获得通道配置信息,再从通道配置信息中获得TaskExecutorRegistration
线程池配置信息,最后从TaskExecutorRegistration
获得ThreadPoolTaskExecutor 实例,作为“clientInboundChannel”的支撑;clientInboundChannelRegistration
为null
,那么将直接new
一个ChannelRegistration
实例,并赋值给成员变量clientInboundChannelRegistration
,同时调用configureClientInboundChannel(registration)
钩子方法,获取WebSocketMessageBrokerConfigurer
提供的自定义配置信息,否则就说明不是第一次调用该方法,直接返回成员变量;AbstractMessageBrokerConfiguration :
public
abstract
class
AbstractMessageBrokerConfiguration
implements
ApplicationContextAware
{
@Nullable
private
ChannelRegistration clientInboundChannelRegistration;
@Bean
public
AbstractSubscribableChannel
clientInboundChannel
() {
ExecutorSubscribableChannel channel = new
ExecutorSubscribableChannel
(
clientInboundChannelExecutor
());
ChannelRegistration reg =
getClientInboundChannelRegistration
();
if (reg.
hasInterceptors
()) {
channel.
setInterceptors
(reg.
getInterceptors
());
}
return
channel;
}
@Bean
public
ThreadPoolTaskExecutor
clientInboundChannelExecutor
() {
TaskExecutorRegistration reg =
getClientInboundChannelRegistration
().
taskExecutor
();
ThreadPoolTaskExecutor executor = reg.
getTaskExecutor
();
executor.
setThreadNamePrefix
("clientInboundChannel-");
return
executor;
}
protected
final
ChannelRegistration
getClientInboundChannelRegistration
() {
if (
this
.clientInboundChannelRegistration == null) {
ChannelRegistration registration = new
ChannelRegistration
();
configureClientInboundChannel
(registration);
registration.
interceptors
(new
ImmutableMessageChannelInterceptor
());
this
.clientInboundChannelRegistration = registration;
}
return
this
.clientInboundChannelRegistration;
}
/**
* A
hook
for
subclasses
to
customize
the
message
channel
for
inbound
messages
*
from
WebSocket
clients
.
*/
protected
void
configureClientInboundChannel
(ChannelRegistration registration) {
}
}
一个相关成员变量
和四个相关方法
,在此不做详述,可以直接类比上面的“配置clientInboundChannel”。AbstractMessageBrokerConfiguration :
public
abstract
class
AbstractMessageBrokerConfiguration
implements
ApplicationContextAware
{
@Nullable
private
ChannelRegistration clientOutboundChannelRegistration;
@Bean
public
AbstractSubscribableChannel
clientOutboundChannel
() {
ExecutorSubscribableChannel channel = new
ExecutorSubscribableChannel
(
clientOutboundChannelExecutor
());
ChannelRegistration reg =
getClientOutboundChannelRegistration
();
if (reg.
hasInterceptors
()) {
channel.
setInterceptors
(reg.
getInterceptors
());
}
return
channel;
}
@Bean
public
ThreadPoolTaskExecutor
clientOutboundChannelExecutor
() {
TaskExecutorRegistration reg =
getClientOutboundChannelRegistration
().
taskExecutor
();
ThreadPoolTaskExecutor executor = reg.
getTaskExecutor
();
executor.
setThreadNamePrefix
("clientOutboundChannel-");
return
executor;
}
protected
final
ChannelRegistration
getClientOutboundChannelRegistration
() {
if (
this
.clientOutboundChannelRegistration == null) {
ChannelRegistration registration = new
ChannelRegistration
();
configureClientOutboundChannel
(registration);
registration.
interceptors
(new
ImmutableMessageChannelInterceptor
());
this
.clientOutboundChannelRegistration = registration;
}
return
this
.clientOutboundChannelRegistration;
}
/**
* A
hook
for
subclasses
to
customize
the
message
channel
for
messages
from
*
the
application
or
message
broker
to
WebSocket
clients
.
*/
protected
void
configureClientOutboundChannel
(ChannelRegistration registration) {
}
}
在看brokerChannel之前,有必要先要了解下ChannelRegistration
——通道配置信息类。该类共持有两个实例:
ExecutorSubscribableChannel
实际上是由ThreadPoolTaskExecutor
线程池作为支撑,而TaskExecutorRegistration
所持有的就是通道的ThreadPoolTaskExecutor
线程池配置信息;另外我们需要理解taskExecutor(taskExecutor)方法:
taskExecutor()
方法不是第一次被调用,那么TaskExecutorRegistration
将不为null
,说明线程池已经被配置,将直接返回配置信息;TaskExecutorRegistration
为null
,那么继续判断;taskExecutor
如果不为null
,那么将把taskExecutor
绑定到TaskExecutorRegistration
——new TaskExecutorRegistration(taskExecutor);taskExecutor
如果为null
,那么直接new TaskExecutorRegistration();ChannelRegistration:
public
class
ChannelRegistration
{
@Nullable
private
TaskExecutorRegistration registration;
private
final
List<
ChannelInterceptor
> interceptors = new
ArrayList
<>();
/**
*
Configure
the
thread
pool
backing
this
message
channel
.
*/
public
TaskExecutorRegistration
taskExecutor
() {
return
taskExecutor
(null);
}
/**
* Configure the thread pool backing this message channel using a custom
* ThreadPoolTaskExecutor.
* @param taskExecutor the executor to use (or {@code null} for a default executor)
*/
public
TaskExecutorRegistration
taskExecutor
(@Nullable ThreadPoolTaskExecutor taskExecutor) {
if (
this
.registration == null) {
this
.registration = (taskExecutor != null ? new
TaskExecutorRegistration
(taskExecutor) :
new
TaskExecutorRegistration
());
}
return
this
.registration;
}
/**
*
Configure
the
given
interceptors
for
this
message
channel
,
*
adding
them
to
the
channel
's
current
list
of
interceptors
.
* @since 4.3.12
*/
public
ChannelRegistration
interceptors
(ChannelInterceptor... interceptors) {
this
.interceptors.
addAll
(Arrays.
asList
(interceptors));
return
this
;
}
/**
* Configure interceptors for the message channel.
* @deprecated as of 4.3.12, in favor of {@link #interceptors(ChannelInterceptor...)}
*/
@Deprecated
public
ChannelRegistration
setInterceptors
(@Nullable ChannelInterceptor... interceptors) {
if (interceptors != null) {
this
.interceptors.
addAll
(Arrays.
asList
(interceptors));
}
return
this
;
}
protected
boolean
hasTaskExecutor
() {
return
(
this
.registration != null);
}
protected
boolean
hasInterceptors
() {
return
!
this
.interceptors.
isEmpty
();
}
protected
List<
ChannelInterceptor
>
getInterceptors
() {
return
this
.interceptors;
}
}
TaskExecutorRegistration
这个类,这个类持有一个ThreadPoolTaskExecutor
实例。这个类有两个构造方法:
taskExecutor
绑定到成员变量上。new
一个ThreadPoolTaskExecutor
实例,其coreSize
核心线程数为Runtime.getRuntime().availableProcessors() * 2 —— 两倍CPUTaskExecutorRegistration:
public
class
TaskExecutorRegistration
{
private
final
ThreadPoolTaskExecutor taskExecutor;
/**
* Create a new {@code TaskExecutorRegistration} for a default
* {@link ThreadPoolTaskExecutor}.
*/
public
TaskExecutorRegistration
() {
this
.taskExecutor = new
ThreadPoolTaskExecutor
();
this
.taskExecutor.
setCorePoolSize
(Runtime.
getRuntime
().
availableProcessors
() * 2);
this
.taskExecutor.
setAllowCoreThreadTimeOut
(
true
);
}
/**
* Create a new {@code TaskExecutorRegistration} for a given
* {@link ThreadPoolTaskExecutor}.
* @param taskExecutor the executor to use
*/
public
TaskExecutorRegistration
(ThreadPoolTaskExecutor taskExecutor) {
Assert.
notNull
(taskExecutor, "
ThreadPoolTaskExecutor
must
not
be
null
");
this
.taskExecutor = taskExecutor;
}
protected
ThreadPoolTaskExecutor
getTaskExecutor
() {
if (
this
.corePoolSize != null) {
this
.taskExecutor.
setCorePoolSize
(
this
.corePoolSize);
}
if (
this
.maxPoolSize != null) {
this
.taskExecutor.
setMaxPoolSize
(
this
.maxPoolSize);
}
if (
this
.keepAliveSeconds != null) {
this
.taskExecutor.
setKeepAliveSeconds
(
this
.keepAliveSeconds);
}
if (
this
.queueCapacity != null) {
this
.taskExecutor.
setQueueCapacity
(
this
.queueCapacity);
}
return
this
.taskExecutor;
}
}
getBrokerRegistry()
代替了getClient**boundChannelRegistration()
、用configureMessageBroker(registry)
代替了configureClient**boundChannel(registration)
,主要是因为前两者只需要配置MessageChannel,而后者既需要配置MessageChannel同时需要配置MessageBroker,所以这里用MessageBrokerRegistry
代替了ChannelRegistration
,而MessageBrokerRegistry
持有了ChannelRegistration
实例,相当于多加了一层;AbstractMessageBrokerConfiguration :
public
abstract
class
AbstractMessageBrokerConfiguration
implements
ApplicationContextAware
{
@Nullable
private
MessageBrokerRegistry brokerRegistry;
@Bean
public
AbstractSubscribableChannel
brokerChannel
() {
ChannelRegistration reg =
getBrokerRegistry
().
getBrokerChannelRegistration
();
ExecutorSubscribableChannel channel = (reg.
hasTaskExecutor
() ?
new
ExecutorSubscribableChannel
(
brokerChannelExecutor
()) : new
ExecutorSubscribableChannel
());
reg.
interceptors
(new
ImmutableMessageChannelInterceptor
());
channel.
setInterceptors
(reg.
getInterceptors
());
return
channel;
}
@Bean
public
ThreadPoolTaskExecutor
brokerChannelExecutor
() {
ChannelRegistration reg =
getBrokerRegistry
().
getBrokerChannelRegistration
();
ThreadPoolTaskExecutor executor;
if (reg.
hasTaskExecutor
()) {
executor = reg.
taskExecutor
().
getTaskExecutor
();
}
else
{
//
Should
never
be
used
executor = new
ThreadPoolTaskExecutor
();
executor.
setCorePoolSize
(0);
executor.
setMaxPoolSize
(1);
executor.
setQueueCapacity
(0);
}
executor.
setThreadNamePrefix
("brokerChannel-");
return
executor;
}
/**
* An accessor for the {@link MessageBrokerRegistry} that ensures its one-time creation
* and initialization through {@link #configureMessageBroker(MessageBrokerRegistry)}.
*/
protected
final
MessageBrokerRegistry
getBrokerRegistry
() {
if (
this
.brokerRegistry == null) {
MessageBrokerRegistry registry = new
MessageBrokerRegistry
(
clientInboundChannel
(),
clientOutboundChannel
());
configureMessageBroker
(registry);
this
.brokerRegistry = registry;
}
return
this
.brokerRegistry;
}
/**
* A hook for subclasses to customize message broker configuration through the
* provided {@link MessageBrokerRegistry} instance.
*/
protected
void
configureMessageBroker
(MessageBrokerRegistry registry) {
}
}
brokerChannel()
方法在构造ExecutorSubscribableChannel
实例时,绑定ThreadPoolTaskExecutor
的逻辑与前两者有所不同,结合上面的分析不难理解下列内容;
Runtime.getRuntime().availableProcessors() * 2
—— 两倍CPUExecutorSubscribableChannel channel = new
ExecutorSubscribableChannel
(client**
boundChannelExecutor
());
brokerChannel
的线程池将被设为null
,Messages将会被使用当前线程同步处理,所以在生产环境中一定要配置brokerChannel
的线程池 ExecutorSubscribableChannel channel = (reg.
hasTaskExecutor
() ?
new
ExecutorSubscribableChannel
(
brokerChannelExecutor
()) : new
ExecutorSubscribableChannel
());
ExecutorSubscribableChannel :
public
class
ExecutorSubscribableChannel
extends
AbstractSubscribableChannel
{
@Nullable
private
final
Executor executor;
/**
* Create a new {@link ExecutorSubscribableChannel} instance
* where messages will be sent in the callers thread.
*/
public
ExecutorSubscribableChannel
() {
this
(null);
}
/**
* Create a new {@link ExecutorSubscribableChannel} instance
* where messages will be sent via the specified executor.
* @param executor the executor used to send the message,
* or {@code null} to execute in the callers thread.
*/
public
ExecutorSubscribableChannel
(@Nullable Executor executor) {
this
.executor = executor;
}
}