subscriptions and publications in the cluster
Using the spring framework for subscriptions and publishing within this app is easy. As our systems become more complex, we need to post messages to other apps. This study will give you a websocket for ordering and publishing messages between different apps.
In a small example, we establish a websocket connection between all nodes to implement the publication and subscription of the message. In this way, the node is both publisher, Subcriber, or broker. We use the Spring app to listen for different messages and broadcast all the messages directly without discrimination. The specific steps are as follows: After starting, open a multicast socket (224.0.0.4:6780), listening to the multicast, while broadcasting its WebSocket address using @service Clustermanager to achieve the need to start after the app, can work properly, To broadcast your own websocket address, example of a ping URL to test whether the correct response to determine whether the other app has been working in the cluster, listen to the broadcast, get the new app WebSocket address, establish a websocket connection Because it is broadcast in the multicast address, all of you will also receive, need to filter out their own websocket address to maintain the connection with their own connected websocket, whether as a server or a client, through the @bean Clustereventmulticaster to implement WebSocket is not part of the spring framework, so you need to incorporate it into the spring frame to support spring's automatic injection publishing message, and if you need to publish to a cluster, Some messages need to be published to the cluster for all established websocket connections, some messages may only need to be published in this app, with Clusterevent to indicate the messages that need to be published to the cluster. The release message is implemented by @bean Clustereventmulticaster, and the receive message to all connection posts is implemented by WebSocket endpoint when app shutdown, close the associated connection close the multicast socket and close the WebSocket connection.
Obviously, this is a n*n websocket connection. In the case of small scale, we may meet our requirements. We can also have a special broker, and WebSocket is the connection between the node and the broker, which is the WebSocket application messaging Protocol, but the small example does not use the specialized broker method. clusterevent
A small example passes the event object directly in the WebSocket, using Java serialization. This approach is simple, but there are limitations, that is, the other side must also be in the Java program. We can also select JSON or XML format for delivery. We have previously learned the basics of serialization and can now use it directly.
public class Clusterevent extends Applicationevent implements serializable{
private static final long Serialversionuid = 1L;
Private final Serializable Serializablesource;
Add rebroadcasted on the basis of previous learning to identify this as an externally received event that does not need to be broadcast to the cluster.
private Boolean rebroadcasted;
Public clusterevent (Serializable source) {
super (source);
This.serializablesource = source;
}
Public Final Boolean isrebroadcasted () {return
rebroadcasted;
}
Public final void setrebroadcasted () {
this.rebroadcasted = true;
}
private void ReadObject (ObjectInputStream in) throws ClassNotFoundException, ioexception{
in.defaultreadobject ( );
This.source = This.serializablesource;
}
We set the relevant event and listener
Public abstract class Authenticationevent extends clusterevent{private static final long serialversionuid = 1L;
Public authenticationevent (Serializable source) {super (source);
} public class Loginevent extends authenticationevent{private static final long serialversionuid = 1L;
Public loginevent (String username) {Super (username); }} @Service public class Authenticationinterestedparty implements applicationlistener<authenticationevent>{PR
Ivate static final Logger log = Logmanager.getlogger ();
@Inject ServletContext ServletContext; @Override public void Onapplicationevent (Authenticationevent event) {log.info ("Authentication Event from Cont
Ext {} received in the context {}. ", Event.getsource (), This.servletContext.getContextPath ()); } @Component public class Logininterestedparty implements applicationlistener<loginevent>{private static fin Al Logger log = Logmanager.getLogger ();
@Inject ServletContext ServletContext; @Override public void Onapplicationevent (Loginevent event) {log.info (' Login event for context {} ' received in
Context {}. ", Event.getsource (), This.servletContext.getContextPath ()); }
}
Clustermanager: Publish your location through the multicast
This is incorporated into the spring framework as a service, and our custom applicationeventmulticaster is Clustereventmulticaster, The specific WebSocket connection is implemented in Clustermessagingendpoint. Spring publishes the Contextrefreshedevent event after the context is initialized, and we can listen to the event as we listen to the previous set of Loginevent.
@Service public class Clustermanager implements applicationlistener<contextrefreshedevent>{...}
Context, including the root context, the web context, and the rest context, in the order of bootstrap, the root context completes initialization first, but at this point the app does not start properly. We can examine the event specifically, whether the last context has been started and completed. In a small example, we use a different approach, and the controller provides a ping interface that, if the app is working properly, the ping interface will respond normally to OK. Ping interface for detecting whether it is working properly
@Controller public
class HomeController {
@RequestMapping ("/ping") public
responseentity<string> Ping () {
httpheaders headers = new Httpheaders ();
Headers.add ("Content-type", "Text/plain;charset=utf-8");
return new responseentity<> ("OK", headers, Httpstatus.ok);
}
Clustermanager Code
@Service public class Clustermanager implements applicationlistener<contextrefreshedevent>{private static final
Logger log = Logmanager.getlogger ();
Multicast is UDP, in this example multicast address is 224.0.0.4, the port for 6780 private static final inetaddress Multicast_group;
private static final int multicast_port = 6780;
static{try {multicast_group = Inetaddress.getbyname ("224.0.0.4");
catch (Unknownhostexception e) {throw new Fatalbeanexception ("Could not initialize IP addresses.", e);
} private Boolean initialized,destroyed = false;
Private MulticastSocket socket;
Private String Pingurl, Messagingurl;
Private Thread Listenthread; @Inject ServletContext ServletContext; Get the servlet context, where you can get the configuration in Web.xml//multicaster is our custom applicationeventmulticaster,
We will be there to maintain and cluster the websocket connections of other apps.
@Inject Clustereventmulticaster Multicaster; "1" Initialization: Create a multicast socket and start listening @PostConstruct public void ListenformuLticastannouncements () throws NumberFormatException, ioexception{//1.1 "initializes the URL for Pingurl and websocket. The host is not automatically acquired here, but is configured, mainly with multiple network adapters, such as a virtual machine installed on the development machine and may be assigned to a different address. In a later multicast setting, you need to specify network interface. So for convenience, small examples are configured in a way.
The Web ports port is also configured in the same way.
String host = Servletcontext.getinitparameter ("host");
if (host = = null) host = Inetaddress.getlocalhost (). gethostaddress ();
String port = servletcontext.getinitparameter ("port");
if (port = = null) port = "8080";
This.pingurl = "http://" + host + ":" + Port + this.servletContext.getContextPath () + "/ping"; This.messagingurl = "ws://" + Host + ":" + Port + this.servletContext.getContextPath () + "/services/messaging/a83teo83hou9
883HHA9 ";
1.2 "Here the creation of the multicast socket, and open the listener in the thread this.socket = new MulticastSocket (multicast_port);"
This.socket.setInterface (host), or to be placed in the Joingroup () before the use of multiple network cards to determine which network card, such as a single network card, without setting This.socket.joinGroup (Multicast_group); This.listenthread = new Thread (This::listen, "Cluster-listener");
Set up the Listener thread This.listenThread.start ();
//"2" after the app is running normally, broadcast your own WebSocket URL through the multicast socket @Async//To ensure that the thread is running. The @Override public void Onapplicationevent (Contextrefreshedevent event) {//2.1 initialized is used to ensure that only one execution is performed, otherwise the root cont
Ext initialization completes once, the Web context initialization completes and executes an if (initialized) return;
initialized = true; "2.2" constantly try to access their own/ping interface, unsuccessful, then Hibernate 500ms, try again, the total number of attempts limited to 120 times, that is, 1 minutes, all attempts to fail, give up try {URL url = new url (th
Is.pingurl);
Log.info ("Attempting to connect to self at {}", url);
int tries = 0;
while (true) {tries + +; (2.2.1) position their/ping to see if the normal response.
Here to learn about the use of urlconnection urlconnection connection = Url.openconnection ();
Connection.setconnecttimeout (100);
Try (InputStream stream = Connection.getinputstream ()) { String response = streamutils.copytostring (stream,standardcharsets.utf_8); if (response!= null && response.equals ("OK")) {//check to see if it is working properly/(2.2.2) app works, where it will be placed via multicast SOC KET, broadcast your own websocket URL (messageurl) to the code datagrampacket packet = new Datagrampacket (this.messaging Url.getbytes (), This.messagingUrl.length (), Multicast_g
Roup, Multicast_port);
This.socket.send (packet);
Return
}else{Log.warn ("Incorrect response: {}", response); }}catch (Exception e) {if (Tries >) {log.fatal ("could n
OT connect to self within seconds. ", e);
Return
} thread.sleep (500L);
} The catch (Exception e) {log.fatal ("Could not connect to self", e); }//"3" Multicast socket listening, if the URL is heard by websocket, connect the URL and establish a websocket connection.
Because it is multicast, it will also receive its own initial broadcast of the WebSocket URL, you need to filter out the private void listen () {byte[] buffer = new byte[2048];
Datagrampacket packet = new Datagrampacket (buffer, buffer.length);
while (true) {try {this.socket.receive (packet); String url = new string (buffer, 0, packet.getlength ());
Get content if (url.length () = = 0) log.warn ("Received blank multicast packet."); else if (url.equals (This.messagingurl))//filter out your WebSocket address log.info ("ignoring our own multicast
Packet from {} ", Packet.getaddress (). gethostaddress ());
Else//3.1 Create a websocket link based on the URL in a custom Applicationeventmulticaster (maintain each websocket connection) This.multicaster.registerNode (URL);
catch (IOException e) {if (this.destroyed) return;
Log.error (e); You should turn off the multicast socket @PreDestroy public void shutdownmulticastconnection () throws Ioexc before the app shuts down.
eption {this.destroyed = true;
try{This.listenThread.interrupt ();
This.socket.leaveGroup (Multicast_group);
}finally{This.socket.close (); }
}
}
RELATED Links: My professional Java for WEB applications related articles