replaced by/topic
). The resulting message is sent to thebrokerChannel
and handled by the message broker. -
The message broker finds all matching subscribers and sends a MESSAGE frame to each one through the
clientOutboundChannel
, from where messages are encoded as STOMP frames and sent on the WebSocket connection.
The next section provides more details on annotated methods, including the kinds of arguments and return values that are supported.
4.4.6. Annotated Controllers
Applications can use annotated @Controller
classes to handle messages from
clients.
Such classes can declare @MessageMapping
, @SubscribeMapping
, and
@ExceptionHandler
methods, as described in the following topics:
@MessageMapping
You can use @MessageMapping
to annotate methods that route messages based on
their
destination. It is supported at the method level as well as at the type level. At the
type
level, @MessageMapping
is used to express shared mappings across all
methods in a
controller.
By default, the mapping values are Ant-style path patterns (for example
/thing*
, /thing/**
),
including support for template variables (for example, /thing/{id}
). The
values can be
referenced through @DestinationVariable
method arguments. Applications can
also switch to
a dot-separated destination convention for mappings, as explained in
Dots
as Separators.
Supported Method Arguments
The following table describes the method arguments:
| Method argument | Description |
|---|---|
|
For access to the complete message. |
|
For access to
the headers within the |
|
For access to the headers through typed accessor methods. |
|
For access to
the payload of the message, converted (for example, from JSON) by a configured
The presence of this annotation is not required since it is, by default, assumed if no other argument is matched. You can annotate payload arguments with |
|
For access to a
specific header value — along with type conversion using an
|
|
For access to
all headers in the message. This argument must be assignable to
|
|
For access to template variables extracted from the message destination. Values are converted to the declared method argument type as necessary. |
|
Reflects the user logged in at the time of the WebSocket HTTP handshake. |
Return Values
By default, the return value from a @MessageMapping
method is serialized
to a payload
through a matching MessageConverter
and sent as a Message
to the brokerChannel
,
from where it is broadcast to subscribers. The destination of the outbound message
is the
same as that of the inbound message but prefixed with /topic
.
You can use the @SendTo
and @SendToUser
annotations to
customize the destination of
the output message. @SendTo
is used to customize the target destination
or to
specify multiple destinations. @SendToUser
is used to direct the output
message
to only the user associated with the input message. See User
Destinations.
You can use both @SendTo
and @SendToUser
at the same time
on the same method, and both
are supported at the class level, in which case they act as a default for methods in
the
class. However, keep in mind that any method-level @SendTo
or @SendToUser
annotations
override any such annotations at the class level.
Messages can be handled asynchronously and a @MessageMapping
method can
return
ListenableFuture
, CompletableFuture
, or CompletionStage
.
Note that @SendTo
and @SendToUser
are merely a convenience
that amounts to using the
SimpMessagingTemplate
to send messages. If necessary, for more advanced
scenarios,
@MessageMapping
methods can fall back on using the SimpMessagingTemplate
directly.
This can be done instead of, or possibly in addition to, returning a value.
See
Sending
Messages.
@SubscribeMapping
@SubscribeMapping
is similar to @MessageMapping
but narrows the
mapping to
subscription messages only. It supports the same
method
arguments as @MessageMapping
. However
for the return value, by default, a message is sent directly to the client (through
clientOutboundChannel
, in response to the subscription) and not to the
broker (through
brokerChannel
, as a broadcast to matching subscriptions). Adding @SendTo
or
@SendToUser
overrides this behavior and sends to the broker instead.
When is this useful? Assume that the broker is mapped to /topic
and /queue
,
while
application controllers are mapped to /app
. In this setup, the broker
stores all
subscriptions to /topic
and /queue
that are intended for
repeated broadcasts, and
there is no need for the application to get involved. A client could also also subscribe
to
some /app
destination, and a controller could return a value in response to
that
subscription without involving the broker without storing or using the subscription
again
(effectively a one-time request-reply exchange). One use case for this is populating a
UI
with initial data on startup.
When is this not useful? Do not try to map broker and controllers to the same destination prefix unless you want both to independently process messages, including subscriptions, for some reason. Inbound messages are handled in parallel. There are no guarantees whether a broker or a controller processes a given message first. If the goal is to be notified when a subscription is stored and ready for broadcasts, a client should ask for a receipt if the server supports it (simple broker does not). For example, with the Java STOMP client, you could do the following to add a receipt:
@Autowired
private TaskScheduler messageBrokerTaskScheduler;
// During initialization..
stompClient.setTaskScheduler(this.messageBrokerTaskScheduler);
// When subscribing..
StompHeaders headers = new StompHeaders();
headers.setDestination("/topic/...");
headers.setReceipt("r1");
FrameHandler handler = ...;
stompSession.subscribe(headers, handler).addReceiptTask(() -> {
// Subscription ready...
});
A server side option is to
register an
ExecutorChannelInterceptor
on the brokerChannel
and implement
the afterMessageHandled
method that is invoked after messages, including subscriptions, have been handled.
@MessageExceptionHandler
An application can use @MessageExceptionHandler
methods to handle exceptions
from
@MessageMapping
methods. You can declare exceptions in the annotation
itself or through a method argument if you want to get access to the exception instance.
The following example declares an exception through a method argument:
@Controller
public class MyController {
// ...
@MessageExceptionHandler
public ApplicationError handleException(MyException exception) {
// ...
return appError;
}
}
@MessageExceptionHandler
methods support flexible method signatures and
support
the same method argument types and return values as
@MessageMapping
methods.
Typically, @MessageExceptionHandler
methods apply within the @Controller
class
(or class hierarchy) in which they are declared. If you want such methods to apply
more globally (across controllers), you can declare them in a class marked with
@ControllerAdvice
. This is comparable to the
similar
support available in Spring MVC.
4.4.7. Sending Messages
What if you want to send messages to connected clients from any part of the
application? Any application component can send messages to the brokerChannel
.
The easiest way to do so is to inject a SimpMessagingTemplate
and
use it to send messages. Typically, you would inject it by
type, as the following example shows:
@Controller
public class GreetingController {
private SimpMessagingTemplate template;
@Autowired
public GreetingController(SimpMessagingTemplate template) {
this.template = template;
}
@RequestMapping(path="/greetings", method=POST)
public void greet(String greeting) {
String text = "[" + getTimestamp() + "]:" + greeting;
this.template.convertAndSend("/topic/greetings", text);
}
}
However, you can also qualify it by its name (brokerMessagingTemplate
), if
another
bean of the same type exists.
4.4.8. Simple Broker
The built-in simple message broker handles subscription requests from clients, stores them in memory, and broadcasts messages to connected clients that have matching destinations. The broker supports path-like destinations, including subscriptions to Ant-style destination patterns.
| Applications can also use dot-separated (rather than slash-separated) destinations. See Dots as Separators. |
If configured with a task scheduler, the simple broker supports STOMP heartbeats. For that, you can declare your own scheduler or use the one that is automatically declared and used internally. The following example shows how to declare your own scheduler:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
private TaskScheduler messageBrokerTaskScheduler;
@Autowired
public void setMessageBrokerTaskScheduler(TaskScheduler taskScheduler) {
this.messageBrokerTaskScheduler = taskScheduler;
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue/", "/topic/")
.setHeartbeatValue(new long[] {10000, 20000})
.setTaskScheduler(this.messageBrokerTaskScheduler);
// ...
}
}
4.4.9. External Broker
The simple broker is great for getting started but supports only a subset of STOMP commands (it does not support acks, receipts, and some other features), relies on a simple message-sending loop, and is not suitable for clustering. As an alternative, you can upgrade your applications to use a full-featured message broker.
See the STOMP documentation for your message broker of choice (such as RabbitMQ, ActiveMQ, and others), install the broker, and run it with STOMP support enabled. Then you can enable the STOMP broker relay (instead of the simple broker) in the Spring configuration.
The following example configuration enables a full-featured broker:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/portfolio").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/topic", "/queue");
registry.setApplicationDestinationPrefixes("/app");
}
}
The following example shows the XML configuration equivalent of the preceding example:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:message-broker application-destination-prefix="/app">
<websocket:stomp-endpoint path="/portfolio" />
<websocket:sockjs/>
</websocket:stomp-endpoint>
<websocket:stomp-broker-relay prefix="/topic,/queue" />
</websocket:message-broker>
</beans>
The STOMP broker relay in the preceding configuration is a Spring
MessageHandler
that handles messages by forwarding them to an external message broker.
To do so, it establishes TCP connections to the broker, forwards all messages to it,
and then forwards all messages received from the broker to clients through their
WebSocket sessions. Essentially, it acts as a “relay” that forwards messages
in both directions.
Add io.projectreactor.netty:reactor-netty and
io.netty:netty-all
dependencies to your project for TCP connection management.
|
Furthermore, application components (such as HTTP request handling methods, business services, and others) can also send messages to the broker relay, as described in Sending Messages, to broadcast messages to subscribed WebSocket clients.
In effect, the broker relay enables robust and scalable message broadcasting.
4.4.10. Connecting to a Broker
A STOMP broker relay maintains a single “system” TCP connection to the broker.
This connection is used for messages originating from the server-side application
only, not for receiving messages. You can configure the STOMP credentials (that is,
the STOMP frame login
and passcode
headers) for this connection.
This is exposed
in both the XML namespace and Java configuration as the systemLogin
and
systemPasscode
properties with default values of guest
and guest
.
The STOMP broker relay also creates a separate TCP connection for every connected
WebSocket client. You can configure the STOMP credentials that are used for all TCP
connections created on behalf of clients. This is exposed in both the XML namespace
and Java configuration as the clientLogin and `clientPasscode
properties with
default
values of guest`and `guest
.
The STOMP broker relay always sets the login and passcode
headers on every CONNECT
frame that it forwards to the broker on behalf of clients. Therefore, WebSocket
clients
need not set those headers. They are ignored. As the Authentication
section explains, WebSocket clients should instead rely on HTTP authentication to
protect
the WebSocket endpoint and establish the client identity.
|
The STOMP broker relay also sends and receives heartbeats to and from the message broker over the “system” TCP connection. You can configure the intervals for sending and receiving heartbeats (10 seconds each by default). If connectivity to the broker is lost, the broker relay continues to try to reconnect, every 5 seconds, until it succeeds.
Any Spring bean can implement ApplicationListener<BrokerAvailabilityEvent>
to receive notifications when the “system” connection to the broker is lost and
re-established. For example, a Stock Quote service that broadcasts stock quotes can
stop trying to send messages when there is no active “system” connection.
By default, the STOMP broker relay always connects, and reconnects as needed if connectivity is lost, to the same host and port. If you wish to supply multiple addresses, on each attempt to connect, you can configure a supplier of addresses, instead of a fixed host and port. The following example shows how to do that:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
// ...
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/queue/", "/topic/").setTcpClient(createTcpClient());
registry.setApplicationDestinationPrefixes("/app");
}
private ReactorNettyTcpClient<byte[]> createTcpClient() {
return new ReactorNettyTcpClient<>(
client -> client.addressSupplier(() -> ... ),
new StompReactorNettyCodec());
}
}
You can also configure the STOMP broker relay with a virtualHost
property.
The value of this property is set as the host
header of every
CONNECT
frame
and can be useful (for example, in a cloud environment where the actual host to which
the TCP connection is established differs from the host that provides the
cloud-based STOMP service).
4.4.11. Dots as Separators
When messages are routed to @MessageMapping
methods, they are matched with
AntPathMatcher
. By default, patterns are expected to use slash (/
)
as the separator.
This is a good convention in web applications and similar to HTTP URLs. However, if
you are more used to messaging conventions, you can switch to using dot (.
) as
the separator.
The following example shows how to do so in Java configuration:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
// ...
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setPathMatcher(new AntPathMatcher("."));
registry.enableStompBrokerRelay("/queue", "/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
The following example shows the XML configuration equivalent of the preceding example:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:message-broker application-destination-prefix="/app" path-matcher="pathMatcher">
<websocket:stomp-endpoint path="/stomp"/>
<websocket:stomp-broker-relay prefix="/topic,/queue" />
</websocket:message-broker>
<bean id="pathMatcher" class="org.springframework.util.AntPathMatcher">
<constructor-arg index="0" value="."/>
</bean>
</beans>
After that, a controller can use a dot (.
) as the separator in @MessageMapping
methods,
as the following example shows:
@Controller
@MessageMapping("red")
public class RedController {
@MessageMapping("blue.{green}")
public void handleGreen(@DestinationVariable String green) {
// ...
}
}
The client can now send a message to /app/red.blue.green123
.
In the preceding example, we did not change the prefixes on the “broker relay”, because those depend entirely on the external message broker. See the STOMP documentation pages for the broker you use to see what conventions it supports for the destination header.
The “simple broker”, on the other hand, does rely on the configured PathMatcher
,
so, if
you switch the separator, that change also applies to the broker and the way the broker
matches
destinations from a message to patterns in subscriptions.
4.4.12. Authentication
Every STOMP over WebSocket messaging session begins with an HTTP request. That can be a request to upgrade to WebSockets (that is, a WebSocket handshake) or, in the case of SockJS fallbacks, a series of SockJS HTTP transport requests.
Many web applications already have authentication and authorization in place to secure HTTP requests. Typically, a user is authenticated through Spring Security by using some mechanism such as a login page, HTTP basic authentication, or another way. The security context for the authenticated user is saved in the HTTP session and is associated with subsequent requests in the same cookie-based session.
Therefore, for a WebSocket handshake or for SockJS HTTP transport requests,
typically, there is already an authenticated user accessible through
HttpServletRequest#getUserPrincipal()
. Spring automatically associates that
user
with a WebSocket or SockJS session created for them and, subsequently, with all
STOMP messages transported over that session through a user header.
In short, a typical web application needs to do nothing
beyond what it already does for security. The user is authenticated at
the HTTP request level with a security context that is maintained through a cookie-based
HTTP session (which is then associated with WebSocket or SockJS sessions created
for that user) and results in a user header being stamped on every Message
flowing
through the application.
Note that the STOMP protocol does have login
and passcode
headers
on the CONNECT
frame. Those were originally designed for and are still needed,
for example, for STOMP over TCP. However, for STOMP over WebSocket, by default,
Spring ignores authorization headers at the STOMP protocol level, assumes that
the user is already authenticated at the HTTP transport level, and expects that
the WebSocket or SockJS session contain the authenticated user.
Spring Security provides
WebSocket
sub-protocol authorization
that uses a ChannelInterceptor to authorize messages based on the user
header in them.
Also, Spring Session provides a
WebSocket
integration
that ensures the user HTTP session does not expire when the WebSocket session is
still active.
|
4.4.13. Token Authentication
Spring Security OAuth provides support for token based security, including JSON Web Token (JWT). You can use this as the authentication mechanism in Web applications, including STOMP over WebSocket interactions, as described in the previous section (that is, to maintain identity through a cookie-based session).
At the same time, cookie-based sessions are not always the best fit (for example, in applications that do not maintain a server-side session or in mobile applications where it is common to use headers for authentication).
The WebSocket protocol, RFC 6455 “doesn’t prescribe any particular way that servers can authenticate clients during the WebSocket handshake.” In practice, however, browser clients can use only standard authentication headers (that is, basic HTTP authentication) or cookies and cannot (for example) provide custom headers. Likewise, the SockJS JavaScript client does not provide a way to send HTTP headers with SockJS transport requests. See sockjs-client issue 196. Instead, it does allow sending query parameters that you can use to send a token, but that has its own drawbacks (for example, the token may be inadvertently logged with the URL in server logs).
| The preceding limitations are for browser-based clients and do not apply to the Spring Java-based STOMP client, which does support sending headers with both WebSocket and SockJS requests. |
Therefore, applications that wish to avoid the use of cookies may not have any good alternatives for authentication at the HTTP protocol level. Instead of using cookies, they may prefer to authenticate with headers at the STOMP messaging protocol level Doing so requires two simple steps:
-
Use the STOMP client to pass authentication headers at connect time.
-
Process the authentication headers with a
ChannelInterceptor
.
The next example uses server-side configuration to register a custom authentication
interceptor. Note that an interceptor needs only to authenticate and set
the user header on the CONNECT Message
. Spring notes and saves the
authenticated
user and associate it with subsequent STOMP messages on the same session. The following
example shows how register a custom authentication interceptor:
@Configuration
@EnableWebSocketMessageBroker
public class MyConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor =
MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if (StompCommand.CONNECT.equals(accessor.getCommand())) {
Authentication user = ... ; // access authentication header(s)
accessor.setUser(user);
}
return message;
}
});
}
}
Also, note that, when you use Spring Security’s authorization for messages, at present,
you need to ensure that the authentication ChannelInterceptor
config is ordered
ahead of Spring Security’s. This is best done by declaring the custom interceptor in
its own implementation of WebSocketMessageBrokerConfigurer
that is marked with
@Order(Ordered.HIGHEST_PRECEDENCE + 99)
.
4.4.14. User Destinations
An application can send messages that target a specific user, and Spring’s STOMP support
recognizes destinations prefixed with /user/
for this purpose.
For example, a client might subscribe to the /user/queue/position-updates
destination.
This destination is handled by the UserDestinationMessageHandler
and
transformed into a destination unique to the user session
(such as /queue/position-updates-user123
). This provides the convenience of
subscribing
to a generically named destination while, at the same time, ensuring no collisions
with other users who subscribe to the same destination so that each user can receive
unique stock position updates.
On the sending side, messages can be sent to a destination such as
/user/{username}/queue/position-updates
, which in turn is translated
by the UserDestinationMessageHandler
into one or more destinations, one for
each
session associated with the user. This lets any component within the application
send messages that target a specific user without necessarily knowing anything more
than their name and the generic destination. This is also supported through an
annotation and a messaging template.
A message-handling method can send messages to the user associated with
the message being handled through the @SendToUser
annotation (also supported on
the class-level to share a common destination), as the following example shows:
@Controller
public class PortfolioController {
@MessageMapping("/trade")
@SendToUser("/queue/position-updates")
public TradeResult executeTrade(Trade trade, Principal principal) {
// ...
return tradeResult;
}
}
If the user has more than one session, by default, all of the sessions subscribed
to the given destination are targeted. However, sometimes, it may be necessary to
target only the session that sent the message being handled. You can do so by
setting the broadcast
attribute to false, as the following example shows:
@Controller
public class MyController {
@MessageMapping("/action")
public void handleAction() throws Exception{
// raise MyBusinessException here
}
@MessageExceptionHandler
@SendToUser(destinations="/queue/errors", broadcast=false)
public ApplicationError handleException(MyBusinessException exception) {
// ...
return appError;
}
}
While user destinations generally imply an authenticated user, it is not strictly
required.
A WebSocket session that is not associated with an authenticated user
can subscribe to a user destination. In such cases, the @SendToUser
annotation
behaves exactly the same as with broadcast=false (that is, targeting
only the
session that sent the message being handled).
|
You can send a message to user destinations from any application
component by, for example, injecting the SimpMessagingTemplate
created by the
Java configuration or
the XML namespace. (The bean name is "brokerMessagingTemplate"
if required
for qualification with @Qualifier
.) The following example shows how to do so:
@Service
public class TradeServiceImpl implements TradeService {
private final SimpMessagingTemplate messagingTemplate;
@Autowired
public TradeServiceImpl(SimpMessagingTemplate messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
// ...
public void afterTradeExecuted(Trade trade) {
this.messagingTemplate.convertAndSendToUser(
trade.getUserName(), "/queue/position-updates", trade.getResult());
}
}
When you use user destinations with an external message broker, you should check the
broker
documentation on how to manage inactive queues, so that, when the user session is
over, all unique user queues are removed. For example, RabbitMQ creates auto-delete
queues when you use destinations such as
/exchange/amq.direct/position-updates .
So, in that case, the client could subscribe to /user/exchange/amq.direct/position-updates .
Similarly, ActiveMQ has
configuration
options
for purging inactive destinations.
|
In a multi-application server scenario, a user destination may remain unresolved because
the user is connected to a different server. In such cases, you can configure a
destination to broadcast unresolved messages so that other servers have a chance to try.
This can be done through the userDestinationBroadcast
property of the
MessageBrokerRegistry
in Java configuration and the user-destination-broadcast
attribute
of the message-broker
element in XML.
4.4.15. Order of Messages
Messages from the broker are published to the clientOutboundChannel
, from where
they are
written to WebSocket sessions. As the channel is backed by a ThreadPoolExecutor
,
messages
are processed in different threads, and the resulting sequence received by the client may
not match the exact order of publication.
If this is an issue, enable the setPreservePublishOrder
flag, as the following
example shows:
@Configuration
@EnableWebSocketMessageBroker
public class MyConfig implements WebSocketMessageBrokerConfigurer {
@Override
protected void configureMessageBroker(MessageBrokerRegistry registry) {
// ...
registry.setPreservePublishOrder(true);
}
}
The following example shows the XML configuration equivalent of the preceding example:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:message-broker preserve-publish-order="true">
<!-- ... -->
</websocket:message-broker>
</beans>
When the flag is set, messages within the same client session are published to the
clientOutboundChannel
one at a time, so that the order of publication is
guaranteed.
Note that this incurs a small performance overhead, so you should enable it only if it is
required.
4.4.16. Events
Several ApplicationContext
events are published and can be
received by implementing Spring’s ApplicationListener
interface:
-
BrokerAvailabilityEvent
: Indicates when the broker becomes available or unavailable. While the “simple” broker becomes available immediately on startup and remains so while the application is running, the STOMP “broker relay” can lose its connection to the full featured broker (for example, if the broker is restarted). The broker relay has reconnect logic and re-establishes the “system” connection to the broker when it comes back. As a result, this event is published whenever the state changes from connected to disconnected and vice-versa. Components that use theSimpMessagingTemplate
should subscribe to this event and avoid sending messages at times when the broker is not available. In any case, they should be prepared to handleMessageDeliveryException
when sending a message. -
SessionConnectEvent
: Published when a new STOMP CONNECT is received to indicate the start of a new client session. The event contains the message that represents the connect, including the session ID, user information (if any), and any custom headers the client sent. This is useful for tracking client sessions. Components subscribed to this event can wrap the contained message withSimpMessageHeaderAccessor
orStompMessageHeaderAccessor
. -
SessionConnectedEvent
: Published shortly after aSessionConnectEvent
when the broker has sent a STOMP CONNECTED frame in response to the CONNECT. At this point, the STOMP session can be considered fully established. -
SessionSubscribeEvent
: Published when a new STOMP SUBSCRIBE is received. -
SessionUnsubscribeEvent
: Published when a new STOMP UNSUBSCRIBE is received. -
SessionDisconnectEvent
: Published when a STOMP session ends. The DISCONNECT may have been sent from the client or it may be automatically generated when the WebSocket session is closed. In some cases, this event is published more than once per session. Components should be idempotent with regard to multiple disconnect events.
| When you use a full-featured broker, the STOMP “broker relay” automatically reconnects the “system” connection if broker becomes temporarily unavailable. Client connections, however, are not automatically reconnected. Assuming heartbeats are enabled, the client typically notices the broker is not responding within 10 seconds. Clients need to implement their own reconnecting logic. |
4.4.17. Interception
Events
provide notifications for the lifecycle
of a STOMP connection but not for every client message. Applications can also register a
ChannelInterceptor
to intercept any message and in any part of the processing
chain.
The following example shows how to intercept inbound messages from clients:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new MyChannelInterceptor());
}
}
A custom ChannelInterceptor
can use StompHeaderAccessor
or SimpMessageHeaderAccessor
to access information about the message, as the following example shows:
public class MyChannelInterceptor implements ChannelInterceptor {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
StompCommand command = accessor.getStompCommand();
// ...
return message;
}
}
Applications can also implement ExecutorChannelInterceptor
, which is a
sub-interface
of ChannelInterceptor
with callbacks in the thread in which the messages are
handled.
While a ChannelInterceptor
is invoked once for each message sent to a channel,
the
ExecutorChannelInterceptor
provides hooks in the thread of each MessageHandler
subscribed to messages from the channel.
Note that, as with the SesionDisconnectEvent
described earlier, a DISCONNECT
message
can be from the client or it can also be automatically generated when
the WebSocket session is closed. In some cases, an interceptor may intercept this
message more than once for each session. Components should be idempotent with regard to
multiple disconnect events.
4.4.18. STOMP Client
Spring provides a STOMP over WebSocket client and a STOMP over TCP client.
To begin, you can create and configure WebSocketStompClient
, as the following
example shows:
WebSocketClient webSocketClient = new StandardWebSocketClient();
WebSocketStompClient stompClient = new WebSocketStompClient(webSocketClient);
stompClient.setMessageConverter(new StringMessageConverter());
stompClient.setTaskScheduler(taskScheduler); // for heartbeats
In the preceding example, you could replace StandardWebSocketClient
with SockJsClient
,
since that is also an implementation of WebSocketClient
. The
SockJsClient
can
use WebSocket or HTTP-based transport as a fallback. For more details, see
SockJsClient
.
Next, you can establish a connection and provide a handler for the STOMP session, as the following example shows:
String url = "ws://<IP_ADDRESS>:8080/endpoint";
StompSessionHandler sessionHandler = new MyStompSessionHandler();
stompClient.connect(url, sessionHandler);
When the session is ready for use, the handler is notified, as the following example shows:
public class MyStompSessionHandler extends StompSessionHandlerAdapter {
@Override
public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
// ...
}
}
Once the session is established, any payload can be sent and is
serialized with the configured MessageConverter
, as the following example
shows:
session.send("/topic/something", "payload");
You can also subscribe to destinations. The subscribe
methods require a handler
for messages on the subscription and returns a Subscription
handle that you can
use to unsubscribe. For each received message, the handler can specify the target
Object
type to which the payload should be deserialized, as the following
example shows:
session.subscribe("/topic/something", new StompFrameHandler() {
@Override
public Type getPayloadType(StompHeaders headers) {
return String.class;
}
@Override
public void handleFrame(StompHeaders headers, Object payload) {
// ...
}
});
To enable STOMP heartbeat, you can configure WebSocketStompClient
with a TaskScheduler
and optionally customize the heartbeat intervals (10 seconds for write inactivity,
which causes a heartbeat to be sent, and 10 seconds for read inactivity, which
closes the connection).
When you use WebSocketStompClient for performance tests to simulate
thousands
of clients from the same machine, consider turning off heartbeats, since each
connection schedules its own heartbeat tasks and that is not optimized for
a large number of clients running on the same machine.
|
The STOMP protocol also supports receipts, where the client must add a receipt
header to which the server responds with a RECEIPT frame after the send or
subscribe are processed. To support this, the StompSession
offers
setAutoReceipt(boolean)
that causes a receipt
header to be
added on every subsequent send or subscribe event.
Alternatively, you can also manually add a receipt header to the StompHeaders
.
Both send and subscribe return an instance of Receiptable
that you can use to register for receipt success and failure callbacks.
For this feature, you must configure the client with a TaskScheduler
and the amount of time before a receipt expires (15 seconds by default).
Note that StompSessionHandler
itself is a StompFrameHandler
, which
lets
it handle ERROR frames in addition to the handleException
callback for
exceptions from the handling of messages and handleTransportError
for
transport-level errors including ConnectionLostException
.
4.4.19. WebSocket Scope
Each WebSocket session has a map of attributes. The map is attached as a header to inbound client messages and may be accessed from a controller method, as the following example shows:
@Controller
public class MyController {
@MessageMapping("/action")
public void handle(SimpMessageHeaderAccessor headerAccessor) {
Map<String, Object> attrs = headerAccessor.getSessionAttributes();
// ...
}
}
You can declare a Spring-managed bean in the websocket
scope.
You can inject WebSocket-scoped beans into controllers and any channel interceptors
registered on the clientInboundChannel
. Those are typically singletons and live
longer than any individual WebSocket session. Therefore, you need to use a
scope proxy mode for WebSocket-scoped beans, as the following example shows:
@Component
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyBean {
@PostConstruct
public void init() {
// Invoked after dependencies injected
}
// ...
@PreDestroy
public void destroy() {
// Invoked when the WebSocket session ends
}
}
@Controller
public class MyController {
private final MyBean myBean;
@Autowired
public MyController(MyBean myBean) {
this.myBean = myBean;
}
@MessageMapping("/action")
public void handle() {
// this.myBean from the current WebSocket session
}
}
As with any custom scope, Spring initializes a new MyBean
instance the first
time it is accessed from the controller and stores the instance in the WebSocket
session attributes. The same instance is subsequently returned until the session
ends. WebSocket-scoped beans have all Spring lifecycle methods invoked, as
shown in the preceding examples.
4.4.20. Performance
There is no silver bullet when it comes to performance. Many factors affect it, including the size and volume of messages, whether application methods perform work that requires blocking, and external factors (such as network speed and other issues). The goal of this section is to provide an overview of the available configuration options along with some thoughts on how to reason about scaling.
In a messaging application, messages are passed through channels for asynchronous executions that are backed by thread pools. Configuring such an application requires good knowledge of the channels and the flow of messages. Therefore, it is recommended to review Flow of Messages.
The obvious place to start is to configure the thread pools that back the
clientInboundChannel
and the clientOutboundChannel
. By default,
both
are configured at twice the number of available processors.
If the handling of messages in annotated methods is mainly CPU-bound, the
number of threads for the clientInboundChannel
should remain close to the
number of processors. If the work they do is more IO-bound and requires blocking
or waiting on a database or other external system, the thread pool size
probably needs to be increased.
|
A common point of confusion is that configuring the core pool size (for example, 10) and max pool size (for example, 20) results in a thread pool with 10 to 20 threads. In fact, if the capacity is left at its default value of Integer.MAX_VALUE, the thread pool never increases beyond the core pool size, since all additional tasks are queued. See the javadoc of |
On the clientOutboundChannel
side, it is all about sending messages to WebSocket
clients. If clients are on a fast network, the number of threads should
remain close to the number of available processors. If they are slow or on
low bandwidth, they take longer to consume messages and put a burden on the
thread pool. Therefore, increasing the thread pool size becomes necessary.
While the workload for the clientInboundChannel
is possible to predict — after
all, it is based on what the application does — how to configure the
"clientOutboundChannel" is harder, as it is based on factors beyond
the control of the application. For this reason, two additional
properties relate to the sending of messages: sendTimeLimit
and sendBufferSizeLimit
. You can use those methods to configure how long a
send is allowed to take and how much data can be buffered when sending
messages to a client.
The general idea is that, at any given time, only a single thread can be used to send to a client. All additional messages, meanwhile, get buffered, and you can use these properties to decide how long sending a message is allowed to take and how much data can be buffered in the meantime. See the javadoc and documentation of the XML schema for important additional details.
The following example shows a possible configuration:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.setSendTimeLimit(15 * 1000).setSendBufferSizeLimit(512 * 1024);
}
// ...
}
The following example shows the XML configuration equivalent of the preceding example:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:message-broker>
<websocket:transport send-timeout="15000" send-buffer-size="524288" />
<!-- ... -->
</websocket:message-broker>
</beans>
You can also use the WebSocket transport configuration shown earlier to configure the maximum allowed size for incoming STOMP messages. In theory, a WebSocket message can be almost unlimited in size. In practice, WebSocket servers impose limits — for example, 8K on Tomcat and 64K on Jetty. For this reason, STOMP clients (such as the JavaScript webstomp-client and others) split larger STOMP messages at 16K boundaries and send them as multiple WebSocket messages, which requires the server to buffer and re-assemble.
Spring’s STOMP-over-WebSocket support does this ,so applications can configure the maximum size for STOMP messages irrespective of WebSocket server-specific message sizes. Keep in mind that the WebSocket message size is automatically adjusted, if necessary, to ensure they can carry 16K WebSocket messages at a minimum.
The following example shows one possible configuration:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.setMessageSizeLimit(128 * 1024);
}
// ...
}
The following example shows the XML configuration equivalent of the preceding example:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:message-broker>
<websocket:transport message-size="131072" />
<!-- ... -->
</websocket:message-broker>
</beans>
An important point about scaling involves using multiple application instances. Currently, you cannot do that with the simple broker. However, when you use a full-featured broker (such as RabbitMQ), each application instance connects to the broker, and messages broadcast from one application instance can be broadcast through the broker to WebSocket clients connected through any other application instances.
4.4.21. Monitoring
When you use @EnableWebSocketMessageBroker
or <websocket:message-broker>
,
key
infrastructure components automatically gather statisticss and counters that provide
important insight into the internal state of the application. The configuration
also declares a bean of type WebSocketMessageBrokerStats
that gathers all
available information in one place and by, default logs, it at the INFO
level
once
every 30 minutes. This bean can be exported to JMX through Spring’s
MBeanExporter
for viewing at runtime (for example, through JDK’s
jconsole
).
The following list summarizes the available information:
- Client WebSocket Sessions
-
- Current
-
Indicates how many client sessions there are currently, with the count further broken down by WebSocket versus HTTP streaming and polling SockJS sessions.
- Total
-
Indicates how many total sessions have been established.
- Abnormally Closed
-
- Connect Failures
-
Sessions that got established but were closed after not having received any messages within 60 seconds. This is usually an indication of proxy or network issues.
- Send Limit Exceeded
-
Sessions closed after exceeding the configured send timeout or the send buffer limits, which can occur with slow clients (see previous section).
- Transport Errors
-
Sessions closed after a transport error, such as failure to read or write to a WebSocket connection or HTTP request or response.
- STOMP Frames
-
The total number of CONNECT, CONNECTED, and DISCONNECT frames processed, indicating how many clients connected on the STOMP level. Note that the DISCONNECT count may be lower when sessions get closed abnormally or when clients close without sending a DISCONNECT frame.
- STOMP Broker Relay
-
- TCP Connections
-
Indicates how many TCP connections on behalf of client WebSocket sessions are established to the broker. This should be equal to the number of client WebSocket sessions + 1 additional shared “system” connection for sending messages from within the application.
- STOMP Frames
-
The total number of CONNECT, CONNECTED, and DISCONNECT frames forwarded to or received from the broker on behalf of clients. Note that a DISCONNECT frame is sent to the broker regardless of how the client WebSocket session was closed. Therefore, a lower DISCONNECT frame count is an indication that the broker is pro-actively closing connections (maybe because of a heartbeat that did not arrive in time, an invalid input frame, or other issue).
- Client Inbound Channel
-
Statistics from the thread pool that backs the
clientInboundChannel
that provide insight into the health of incoming message processing. Tasks queueing up here is an indication that the application may be too slow to handle messages. If there I/O bound tasks (for example, slow database queries, HTTP requests to third party REST API, and so on), consider increasing the thread pool size. - Client Outbound Channel
-
Statistics from the thread pool that backs the
clientOutboundChannel
that provides insight into the health of broadcasting messages to clients. Tasks queueing up here is an indication clients are too slow to consume messages. One way to address this is to increase the thread pool size to accommodate the expected number of concurrent slow clients. Another option is to reduce the send timeout and send buffer size limits (see the previous section). - SockJS Task Scheduler
-
Statistics from the thread pool of the SockJS task scheduler that is used to send heartbeats. Note that, when heartbeats are negotiated on the STOMP level, the SockJS heartbeats are disabled.
4.4.22. Testing
There are two main approaches to testing applications when you use Spring’s STOMP-over-WebSocket support. The first is to write server-side tests to verify the functionality of controllers and their annotated message-handling methods. The second is to write full end-to-end tests that involve running a client and a server.
The two approaches are not mutually exclusive. On the contrary, each has a place in an overall test strategy. Server-side tests are more focused and easier to write and maintain. End-to-end integration tests, on the other hand, are more complete and test much more, but they are also more involved to write and maintain.
The simplest form of server-side tests is to write controller unit tests. However, this is not useful enough, since much of what a controller does depends on its annotations. Pure unit tests simply cannot test that.
Ideally, controllers under test should be invoked as they are at runtime, much like the approach to testing controllers that handle HTTP requests by using the Spring MVC Test framework — that is, without running a Servlet container but relying on the Spring Framework to invoke the annotated controllers. As with Spring MVC Test, you have two two possible alternatives here, either use a “context-based” or use a “standalone” setup:
-
Load the actual Spring configuration with the help of the Spring TestContext framework, inject
clientInboundChannel
as a test field, and use it to send messages to be handled by controller methods. -
Manually set up the minimum Spring framework infrastructure required to invoke controllers (namely the
SimpAnnotationMethodMessageHandler
) and pass messages for controllers directly to it.
Both of these setup scenarios are demonstrated in the tests for the stock portfolio sample application.
The second approach is to create end-to-end integration tests. For that, you need to run a WebSocket server in embedded mode and connect to it as a WebSocket client that sends WebSocket messages containing STOMP frames. The tests for the stock portfolio sample application also demonstrate this approach by using Tomcat as the embedded WebSocket server and a simple STOMP client for test purposes.
5. Other Web Frameworks
This chapter details Spring’s integration with third-party web frameworks.
One of the core value propositions of the Spring Framework is that of enabling choice. In a general sense, Spring does not force you to use or buy into any particular architecture, technology, or methodology (although it certainly recommends some over others). This freedom to pick and choose the architecture, technology, or methodology that is most relevant to a developer and their development team is arguably most evident in the web area, where Spring provides its own web frameworks (Spring MVC and Spring WebFlux) while, at the same time, supporting integration with a number of popular third-party web frameworks.
5.1. Common Configuration
Before diving into the integration specifics of each supported web framework, let us first take a look at common Spring configuration that is not specific to any one web framework. (This section is equally applicable to Spring’s own web framework variants.)
One of the concepts (for want of a better word) espoused by Spring’s lightweight
application model is that of a layered architecture. Remember that in a “classic”
layered architecture, the web layer is but one of many layers. It serves as one of the
entry points into a server-side application, and it delegates to service objects
(facades) that are defined in a service layer to satisfy business-specific (and
presentation-technology agnostic) use cases. In Spring, these service objects, any other
business-specific objects, data-access objects, and others exist in a distinct “business
context”, which contains no web or presentation layer objects (presentation objects
,such as Spring MVC controllers, are typically configured in a distinct “presentation
context”). This section details how you can configure a Spring container (a
WebApplicationContext
) that contains all of the 'business beans' in your
application.
Moving on to specifics, all you one need to do is declare a
ContextLoaderListener
in the standard Java EE servlet web.xml
file of your web application and add a
contextConfigLocation
<context-param/> section (in the same file) that defines
which
set of Spring XML configuration files to load.
Consider the following <listener/>
configuration:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Further consider the following <context-param/>
configuration:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
If you do not specify the contextConfigLocation
context parameter, the
ContextLoaderListener
looks for a file called
/WEB-INF/applicationContext.xml
to
load. Once the context files are loaded, Spring creates a
WebApplicationContext
object based on the bean definitions and stores it in the ServletContext
of the web
application.
All Java web frameworks are built on top of the Servlet API, so you can use the
following code snippet to get access to this “business context” ApplicationContext
created by the ContextLoaderListener
.
The following example shows how to get the WebApplicationContext
:
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
The
WebApplicationContextUtils
class is for convenience, so you need not remember the name of the ServletContext
attribute. Its getWebApplicationContext()
method returns null
if an
object
does not exist under the
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
key. Rather than risk getting NullPointerExceptions
in your application, it is
better
to use the getRequiredWebApplicationContext()
method. This method throws an
exception
when the ApplicationContext
is missing.
Once you have a reference to the WebApplicationContext
, you can retrieve beans by
their
name or type. Most developers retrieve beans by name and then cast them to one of their
implemented interfaces.
Fortunately, most of the frameworks in this section have simpler ways of looking up beans. Not only do they make it easy to get beans from a Spring container, but they also let you use dependency injection on their controllers. Each web framework section has more detail on its specific integration strategies.
5.2. JSF
JavaServer Faces (JSF) is the JCP’s standard component-based, event-driven web user interface framework. It is an official part of the Java EE umbrella but also individually usable, e.g. through embedding Mojarra or MyFaces within Tomcat.
Please note that recent versions of JSF became closely tied to CDI infrastructure in application servers, with some new JSF functionality only working in such an environment. Spring’s JSF support is not actively evolved anymore and primarily exists for migration purposes when modernizing older JSF-based applications.
The key element in Spring’s JSF integration is the JSF ELResolver
mechanism.
5.2.1. Spring Bean Resolver
SpringBeanFacesELResolver
is a JSF compliant ELResolver
implementation,
integrating with the standard Unified EL as used by JSF and JSP. It delegates to
Spring’s “business context” WebApplicationContext
first and then to the
default resolver of the underlying JSF implementation.
Configuration-wise, you can define SpringBeanFacesELResolver
in your JSF
faces-context.xml
file, as the following example shows:
<faces-config>
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
...
</application>
</faces-config>
5.2.2.
Using FacesContextUtils
A custom ELResolver
works well when mapping your properties to beans in
faces-config.xml
, but, at times, you may need to explicitly grab a bean.
The
FacesContextUtils
class makes this easy. It is similar to WebApplicationContextUtils
, except that
it takes a FacesContext
parameter rather than a ServletContext
parameter.
The following example shows how to use FacesContextUtils
:
ApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
5.3. Apache Struts 2.x
Invented by Craig McClanahan, Struts is an open-source project hosted by the Apache Software Foundation. At the time, it greatly simplified the JSP/Servlet programming paradigm and won over many developers who were using proprietary frameworks. It simplified the programming model, it was open source (and thus free as in beer), and it had a large community, which let the project grow and become popular among Java web developers.
As a successor to the original Struts 1.x, check out Struts 2.x and the Struts-provided Spring Plugin for the built-in Spring integration.
5.4. Apache Tapestry 5.x
Tapestry is a ""Component oriented framework for creating dynamic, robust, highly scalable web applications in Java.""
While Spring has its own powerful web layer, there are a number of unique advantages to building an enterprise Java application by using a combination of Tapestry for the web user interface and the Spring container for the lower layers.
For more information, see Tapestry’s dedicated integration module for Spring.


--- layout: post title: SEPAT date: 2007-08-17 06:54:32.000000000 -05:00 type: post parent_id: '0' published: true password: '' status: publish categories: - English - Korea'07 tags: [] meta: _oembed_7fc28488cbc8ccd3035c551d243952fb: "{{unknown}}" author: login: dreamessenceonthemove email<EMAIL_ADDRESS>display_name: darribas first_name: Daniel last_name: Arribas-Bel permalink: "/2007/08/17/59/" ---
Yesterday I was walkking around the old centre of Taipei almost all the day long. I the night, I met my friend from Sweden and some friends of her for a drink, trying to get deeper into taiwanese culture, hehe. Today I've just waken up and had breakfast and now waiting for my friend coming from Taijung this morning. We'll stay in Taipei at least one more day and, if the weather allows us, we'll go travelling the island around on sunday or monday.
The only con is this:
Typhoon SEPAT
A large & very powerful storm. Strongest winds are at the center of the storm, upwards of 155mph/250kph making it a Category 4 hurricane in the west. Will begin Influencing the island Friday morning 8/17. Landfall forecast for Hualien Taidong on Saturday morning 8/18 around 5am. On Saturday 8/18 strongest winds will be in Hualien/Taidong, while heaviest rains are forecast for North & NE Taiwan. The storm should be past the Island by Sunday 8/19.
Source: http://www.tealit.com/article_categories.php?section=weather&article=typhoon
Yet, locals are not that worried, neither am I. It looks like it'll last for 2 or 3 days and the precaution we are required to take is staying away from he mountains and the beach and shuting down AC and windows. I guess I can handle it. Mom, Dad, I'll be safe ;)


--- layout: splash title: "University of Alberta Aerial Robotics Group" header: overlay_color: "#5e616c" overlay_image: site-splash.jpg cta_label: " Find Out More" cta_url: "/about/" caption: excerpt: 'We design, build, and fly Unmanned Aerial Vehicles (UAVs) for student competitions.' ---


Toast can be dismissed with a swipe, a timer, or a button. Notice the 'Show Custom' toast will not nudge the FABs positions since a custom parent was specified.


Chapter 4 Inference and sample
- Make the difference between individual variation and sample variation
- Make the difference between observed values and estimated parameters
- Interpret a confidence interval
- Interpret a statistical test
4.1 Sample
4.1.1 Population versus Sample
Why take a sample … to conclude on the population?
When the population is small and isolated, like an Inuit village in Greenland for instance, it is relevant to study/interrogate the entire population to get the exact prevalence of a rare disease (Figure 4.1).
However if the size of the population is large we might not be able (want) to get it all! It is time consuming, costs a lot, and we are smarter. Although we will conclude on the population, a well design sample allows an estimation of the prevalence of the outcome of interest.
What is the main property of a good sample?
- Since we draw conclusions about a population based on the information obtained from a sample (subset of the population), it is important that the units of interest in the sample are representative of the entire population.
- A representative sample will allow to confidently generalize the results and the conclusion of your study
- Poor sampling designs can yield misleading conclusions
- Set of observations drawn from a population
- All the individuals of the study population should have the same probability of being drawn
-
A
representative sample
should be an unbiased reflection of what the targeted population is like for the units of interest (outcome and covariates/determinants) - A representative sample for a variable should reflect the variable distribution observed in the targeted population.
For example, you plan to determine the relationship between gratitude and job satisfaction in gynecologists. Your sample might consist of 30 to 40 gynecologists. Your population might be “gynecologists in the United States,” or, if the scope of your study was more narrow, “gynecologists in New York City.” So, if most gynecologists in the population are women, but your sample is all male, you do not have a good case for representativeness because your sample does not share the same characteristics as the larger population. In this case, you cannot generalize the results of your study to the population.
4.1.2 Sample designs
| Element selection technique | Probability sampling | Non-probability sampling |
|---|---|---|
| Unrestricted sampling | Simple random sampling | Convenience sampling (Voluntary response) |
| Restricted sampling | Complex random sampling (systematic sampling, stratified sampling) | Purposive sample (such as quota sampling) |
4.1.3 Probability sampling
- Simple random sample of size n consists of n individuals from the population chosen in such a way that every set of n individuals has an equal chance to be the sample actually selected.
The simple random sampling is the gold standard: All individuals are given an equal chance to be chosen to be in the sample.
- Stratified random samples (or block experiment) define by strata of similar characteristics and choose a separate simple random sample (SRS) in each stratum and combine these to form the full sample.
- Cluster and multistage samples consist of all or random units within clusters (hierarchical sampling)
For example, the HBSC study is based on a multistage sampling. In France, in each region some schools were randomly selected, within a school some classes were randomly selected and all the students of the selected class were interrogate.
The Dean of the School of public health wants to meet with several members of the faculty of the Department of Statistics to discuss concerns they might have about their department. He does not have time to talk to all of the faculty members, but wants to be sure that he meets with faculty with various levels of seniority.
The Department of Statistics is composed of:
18 Professors
3 Associate Professors
5 Assistant Professors
The Dean decides to speak with 5 Professors, 2 Associate Professors, and 3 Assistant Professors. What sampling design can be used?
- Systematic sampling
Sometimes we draw a sample by selecting individuals systematically. For example, a systematic sample might select every tenth person entering a school cafeteria (price, food quality, opening hours…). To make sure our sample is random, we still must start the systematic selection with a randomly selected individual, not necessarily the first person entering the cafeteria at lunchtime. When there is no reason to believe that the order of people entering the pool could be associated in any way with the responses measured.
4.1.4 Non-probability sampling
Voluntary response survey In a voluntary response sample, a large group of individuals is invited to respond, and all who do respond are counted. This method is used by call-in shows, Internet polls, Political party survey. Voluntary response samples are almost always biased, and so conclusions drawn from them are almost always wrong.
For example, the ABC news program Nightline once asked their viewers whether the United Nations should continue to have its headquarters in the United States. In order to have their opinions counted, viewers had to call a 1-900 number and pay a small fee. More than 186,000 callers responded and 67\(\%\) said “No.” The callers of such program tend to be strong headed and often negative opinions. A nationwide poll with a proper sampling design found that less than 28 \(\%\) of US adults want the UN to move out of the United States.
Convenience sampling chooses the individuals who are convenient, the easiest to reach to be in the sample. The group is probably not representative of the targeted population. This method is used in shopping area (street, mall). This population tend to be more affluent and include a larger percentage of teenagers and retirees than the population at large.
For example, you interview people at the mall or on a street corner about the French school policy that allows every cities to decide whether school schedule is spread over 4 or 5 days per week.
Other non-probability sampling methods exists but are largely bias. One has to be aware and truthful when concluding on such samples.
4.1.5 Sampling bias
When a sample is biased, the summary characteristics of a sample differ from the corresponding characteristics of the population it is trying to represent.
- Undercoverage: some portion of the population is not sampled at all or has a smaller representation in the sample than it has in the population.
- Non-response: those who don???t respond may differ from those who do
- Comparability
- Wording of questions: influence the answers by presenting one side of an issue consciously or not
- Response bias: tendency to please the interviewer
4.2 Confidence intervals
4.2.1 Within and between sample variation
As shown in Figure 4.9, individual measures vary with a sample. The standard deviation \(s\) is a indicator of that individual fluctuation
. It is the average distance of the measures of the individuals to the mean.
If you drawn different samples from the same population you will get different means (Figure 4.10) due to sampling fluctuation
or sampling distribution of the mean
. This variance between the means of different samples can be estimated by the standard deviation of this sampling distribution and it is the standard error (SE) of the estimate of the mean.
The standard error (SE) is a type of standard deviation for the distribution of the means of samples drawn from the same population.
\(\sigma_\mu = s/\sqrt{n}\)
where:
- \(\sigma_\mu\) standard error of the mean
- \(s\) standard deviation of the sample (3.3.2)
- \(n\) size of the sample
4.2.2 The CLT and the confidence interval
The mean \(m\) in a sample of size \(n\) is a random variable, which varies between samples. This random variables should follow a Normal distribution centered around \(\mu\), the true mean of the population. This is the central Limit Theorem
.
Central Limit Theorem (CLT)
The mean of a random sample has a sampling distribution whose shape can be approximated by a Normal model. The larger the sample, the better the approximation will be.
For example, in the HBSC survey the observed mean of weights of 11 years-old French children in 2006 in our sample (n=500) is 38, 55 Kg (s = 8,10 Kg). How do we estimate the TRUE value in the population of children aged 11 in 2006 in France?
Using central limit theorem, one can demonstrate that we can be 95% confident that the true mean \(\mu\) of the population from which is extracted our sample is within the interval:
\(m-1.96*\sigma_\mu \leq \mu \leq m+1.96*\sigma_\mu\)
where:
- \(\sigma_\mu\) standard error of the mean
- \(m\) mean of the sample
- 1.96 multiplier coefficient that depends on the confidence level expected
Following the example, the CI95% will be [37.40Kg-39.85Kg].
Similarly the proportion \(p\) in a sample of size \(n\) is a ramdon variable, which varies between samples. This random variables follows a Normal distribution centered around \(\pi\).
For example, you are interested in the proportion of children (aged 2-3) with sleeping disorder in Isere, France (population: 14 000 children of 2 or 3 years old). You built a sample of 540 children among which 86 had sleeping disorder. The proportion of children with sleeping disorder in our sample is \(p=16\)%. But what is the TRUE proportion of children (aged 2-3) with sleeping disorder in Isere?
Using central limit theorem, one can demonstrate that we can be 95% confident that the true proportion \(\pi\) of the population from which is extracted our sample is within the interval:
\(p-1.96*\sigma_\pi \leq \pi \leq p+1.96*\sigma_\pi\)
where:
- \(p=k/n\), \(k\) is the number of entities with the characteristic and \(n\) the size of the sample
- \(\sigma_\pi\) standard error of a proportion \(\sqrt{p(1-p)/n}\)
- 1.96 multiplier coefficient that depends on the confidence level expected
Following the example, the CI95% will be [12.9% ; 19.1%].
4.2.3 Interpretation of confidence intervals
The true mean is or is not in your estimated confidence interval. At 95% confidence, You took an 5%-risk of having the wrong confidence interval.
In Figure 4.12, 19 out of 20 samples (95%) from the same population will produce confidence intervals that contain the TRUE population parameter. There is a 95% probability that the calculated confidence interval encompasses the true value of the population parameter
For example, in the HBSC sample and the age group [11-13[ years old, the mean weight is 38.61Kg. But what is the true mean in the population?
## n mean sd se lower95ci upper95ci
## 167 38.60539 8.156085 0.6311368 37.3593 39.85148
where:
- \(n\) is the size of the sample
- \(sd\) standard deviation of the sample
- \(se\) standard error of population mean
- \(lower95ci\) lower bound of the 95% confidence interval
- \(upper95ci\) upper bound of the 95% confidence interval
We cannot give a unique true answer but only an interval (an estimation) with a certain confidence. We will say that in our sample the punctual estimate of the mean of weights for student aged 11 in France in 2006 was 38.60 kg and that we are 95% confident that in 2006, among the entire population of 11 year-old French student, the mean of weights is between 37.40Kg and 39.85Kg (CI95% [37.40Kg-39.85Kg]).
For the proportion example, we are 95% confident that the true proportion of children, aged 2-3, with sleeping disorder in Isere is between 12.9% and 19.1%.
4.2.4 Why 1.96?
We can generalize the equation above to:
\(m-Z_\alpha\sigma_\mu \leq \mu \leq m+Z_\alpha\sigma_\mu\)
where:
- \(Z_\alpha\) is the critical value of the Normal distribution (centered on \(\mu=0\), reduced to \(\sigma=1\)) where \(100-\alpha\) % of the values stand within \(Z\) standard deviations of the mean.
The critical value \(Z_\alpha\) will be larger or smaller when computing a confidence interval at 90?
4.2.5 Precision or Margin error
The term \(Z_\alpha\sigma_\mu\) or \(Z_\alpha\sigma_\pi\) is noted \(i\) and named the precision
or margin error
of the confidence interval.
In a simple random sample, the precision is proportional to the square root of the inverse of the sample size. It is not linear!
For example, what should be the size of the sample to estimate the prevalence of overweight children aged 12, in Haute Savoie with a precision of \(i\) knowing from the literature that the estimate prevalence is 17%?
From the equation of the confidence interval of a proportion is \(n=P(P-1)Z_\alpha^2/i^2\)
For a precision of 3%, \(n = 0.17(1-0.17)*1.96^2/0.03^2 = 627\)
For a precision of 1%, \(n = 0.17(1-0.17)*1.96^2/0.01^2 = 5644\) !!!


Please Follow TruthTrolly
Post #1
Aadhaar Card Update:
Now you can Easily Change Date of Birth, Mobile No, Address on Aadhaar on online
link >>


Some content.
| text with line through |
| text with overline |
| font-family | Example text |
|---|---|
| "Courier New", Courier, monospace | This is a headingThis is a paragraph |
| "Lucida Console", Monaco, monospace | This is a headingThis is a paragraph |
| font-family | Example text |
|---|---|
| Arial, Helvetica, sans-serif | This is a headingThis is a paragraph |
| "Arial Black", Gadget, sans-serif | This is a headingThis is a paragraph |
| "Comic Sans MS", cursive, sans-serif | This is a headingThis is a paragraph |
| Impact, Charcoal, sans-serif | This is a headingThis is a paragraph |
| "Lucida Sans Unicode", "Lucida Grande", sans-serif | This is a headingThis is a paragraph |
| Tahoma, Geneva, sans-serif | This is a headingThis is a paragraph |
| "Trebuchet MS", Helvetica, sans-serif | This is a headingThis is a paragraph |
| Verdana, Geneva, sans-serif | This is a headingThis is a paragraph |
| font-family | Example text |
|---|---|
| "Courier New", Courier, monospace | This is a headingThis is a paragraph |
| "Lucida Console", Monaco, monospace | This is a headingThis is a paragraph |
Example of ordered lists:
|
ExampleThe border-color property is used to set the color of the border. The color can be set by: name - specify a color name, like "red" RGB - specify a RGB value, like "rgb(255,0,0)" Hex - specify a hex value, like "#ff0000" |
Text inside the transparent box, and it looks nice. Text inside the transparent box, and it looks nice. Text inside the transparent box, and it looks nice. Text inside the transparent box, and it looks nice. Text inside the transparent box, and it looks nice. Text inside the transparent box, and it looks nice.
How to Practice Random Acts of Kindness Random acts of kindness are a means by which we make a deliberate attempt to brighten another person's day by doing something thoughtful, nice, and caring for them. Kindness is a way of showing others that they count and that even in the face of hostility and selfishness, you're making a stand for kindness. Originally associated with Anne Herbert, who is said to have once written "Practice random acts of kindness and senseless acts of beauty" on a place mat in a restaurant,[1] this concept has become an organized celebration through various events around the world, as well as referring to a general call to action in the name of kindness. And you don't need to wait for someone else to instigate a day or week of celebrations to practice random acts of kindness; you can put them into play any time you like! By doing kind acts for others, you're helping to create kindness-aware communities that value generosity of spirit and action and kindness toward others as essential parts of a healthy community. Here are some suggestions for encouraging others with your random acts of kindness.
The whole problem is that floated objects do not add to the height of the
object the reside in properly. As you can see below, these divs with the class
"floated_box" are within the div "main_container", yet on the page they are
outside that container div.
solution:
Put this empty div AFTER your last floated object

Some content.
Some content.
this is random.
this is nothing.


{% extends "base.html" %}
{% block title %}
Rapid Meeting Reasons
{% endblock %}
{% block maintitle %}
Rapid Meeting Reasons for {{ pi.displayName }}
{% endblock %}
{% block content %}
{{ report|safe }}
Thank you for submitting the meeting feedback. As your token reward, here is more cowbell!
{% endblock %}


Reload this page to see if your transaction has been mined.
continue
When you make a Bitcoin transaction, it must be mined to be actual part of the blockchain, and thus, acknowledged.