Introduction
Observer pattern: a plurality of viewers simultaneously monitor a theme object when the subject is the object changes, it's all observers will be notified.
Such as micro-channel public number, when the author issued a document, all subscribers will receive. Such observer mode can achieve broadcast, while in line with the principle of opening and closing, adding new viewers without changing the original code.
The observer pattern UML diagram below
Subject (theme): defines the set of observers from registration, delete, notification observer method
ConcreteSubject (specific topic)
the Observer (observers): defines the theme changes made upon receipt of notification
ConcreteObserver (particularly observer)
Handwriting observer mode
To the public micro-channel number, for example to write an observer mode
Abstract theme
public interface MySubject {
void registerObserver(MyObserver o);
void removeObserver(MyObserver o);
void notifyObserver();
}
Abstract observer
public interface MyObserver {
void update(String authorName, String articleName);
}
Specific topics
public class WeChatServer implements MySubject {
private List<MyObserver> myObservers;
private String authorName;
private String articleName;
public WeChatServer(String authorName) {
myObservers = new ArrayList<>();
this.authorName = authorName;
}
public void publishArticle(String articleName) {
this.articleName = articleName;
notifyObserver();
}
@Override
public void registerObserver(MyObserver o) {
myObservers.add(o);
}
@Override
public void removeObserver(MyObserver o) {
if (myObservers.contains(o)) {
myObservers.remove(o);
}
}
@Override
public void notifyObserver() {
myObservers.forEach(item -> {
item.update(authorName, articleName);
});
}
}
Specific observer
public class WeChatClient implements MyObserver {
private String username;
public WeChatClient(String username) {
this.username = username;
}
@Override
public void update(String authorName, String articleName) {
System.out.println(username + ": " + authorName + " 发了一篇文章 " + articleName);
}
}
Test category
public class Main {
public static void main(String[] args) {
WeChatServer weChatServer = new WeChatServer("Java识堂");
WeChatClient user1 = new WeChatClient("张三");
WeChatClient user2 = new WeChatClient("李四");
weChatServer.registerObserver(user1);
weChatServer.registerObserver(user2);
weChatServer.publishArticle("《五分钟学会观察者模式》");
}
}
Output
张三: Java识堂 发了一篇文章 《五分钟学会观察者模式》
李四: Java识堂 发了一篇文章 《五分钟学会观察者模式》
Application observer pattern
JDK provides the observer mode interface
Java has observer mode support in java.util package, which defines two interfaces
Abstract observer
public interface Observer {
void update(Observable o, Object arg);
}
Abstract theme
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
And we are very similar to the previously defined Kazakhstan, but more a change of the switching field, and to ensure the security thread
Let's rewrite the previous example about the definition of the event object
@Data
@AllArgsConstructor
public class NewArticleEvent {
private String authorName;
private String articleName;
}
public class WeChatServer extends Observable {
private String authorName;
private String articleName;
public WeChatServer(String authorName) {
this.authorName = authorName;
}
public void publishArticle(String articleName) {
setChanged();
this.articleName = articleName;
notifyObservers(new NewArticleEvent(authorName, articleName));
}
}
public class WeChatClient implements Observer {
private String username;
public WeChatClient(String username) {
this.username = username;
}
@Override
public void update(Observable o, Object arg) {
NewArticleEvent event = (NewArticleEvent) arg;
System.out.println(username + ": " + event.getAuthorName() + " 发了一篇文章 " + event.getAuthorName());
}
}
public class Main {
public static void main(String[] args) {
WeChatServer weChatServer = new WeChatServer("Java识堂");
WeChatClient user1 = new WeChatClient("张三");
WeChatClient user2 = new WeChatClient("李四");
weChatServer.addObserver(user1);
weChatServer.addObserver(user2);
weChatServer.publishArticle("《五分钟学会观察者模式》");
}
}
Output Same as above
Custom event in the spring
Spring observer mode to achieve with the event listener, the event listener is relatively simple to achieve in the spring, or to transform what the above example
Event Type classes need to inherit ApplicationEvent
@Data
public class NewArticleEvent extends ApplicationEvent {
private String authorName;
private String articleName;
public NewArticleEvent(Object source, String authorName, String articleName) {
super(source);
this.authorName = authorName;
this.articleName = articleName;
}
}
We can be realized by implementing event listeners ApplicationListener interface or use @EventListener comment
@Component
public class NewArticleEventListener implements ApplicationListener<NewArticleEvent> {
@Override
public void onApplicationEvent(NewArticleEvent event) {
System.out.println(event.getAuthorName() + " 发了一篇文章 " + event.getArticleName());
}
}
@Component
public class MyEventListener {
@EventListener
public void newArticleEventListener(NewArticleEvent event) {
System.out.println(event.getAuthorName() + " 发了一篇文章 " + event.getArticleName());
}
}
The above example was made viewers in two ways, the following test class start writing. The above classes in the package Ha com.javashitang.part6
@Configuration
@ComponentScan("com.javashitang.part6")
public class AppConfig {
}
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
context.publishEvent(new NewArticleEvent(context, "Jva识堂", "《五分钟学会观察者模式》"));
context.close();
}
}
At this point you can see the console output
Jva识堂 发了一篇文章 《五分钟学会观察者模式》
Jva识堂 发了一篇文章 《五分钟学会观察者模式》
Well, now you'll have a custom event in the spring. Achieve spring in the observer pattern may complicated, but the basic idea is mentioned above.
- Spring is ApplicationEvent event interface
- Spring is ApplicationListener event listener interface, all of the listeners have to implement the interface
- Spring is ApplicationEventPublisher event publishing interface, ApplicationContext implements this interface
spring offers some ApplicationEvent implementation class for us
- ContextStartedEvent: ApplicationContext container issued during initialization of the event type
- ContextClosedEvent: ApplicationContext container published in going to shut down the event type
- ContextRefreshedEvent: ApplicationContext container published in the initialization or refresh when the event type
If you want to know a good application of spring events in the project definition. You can see my previous article, we look at how to use annotations + spring events to implement the strategy pattern
Project if else too, how to reconstruct?
User - defined event in spring-cloud-eureka in
We all know that eureka is a registry, save the service name -> ip address specific relationship, it is
ConcurrentHashMap to save the mapping relationship. Since it is certainly related to the registration center to register and cancel services, eureka in the register (registration), cancel (cancel), when renew (renewal) happens, will publish an event, as shown in the following code
InstanceRegistry.java
private void handleRegistration(InstanceInfo info, int leaseDuration,
boolean isReplication) {
log("register " + info.getAppName() + ", vip " + info.getVIPAddress()
+ ", leaseDuration " + leaseDuration + ", isReplication "
+ isReplication);
publishEvent(new EurekaInstanceRegisteredEvent(this, info, leaseDuration,
isReplication));
}
If you are more interested in information services, such as data persistence want, you can listen to these events, scalability is not particularly good?
Reference blog
[1] https://juejin.im/post/5bcf53f351882577e5120b99#heading-8
the Spring the Boot whole process, there is an event part
[2] https://www.jianshu.com/p/83693d3d0a65
[3] HTTPS: // Blog .lqdev.cn / 2018/11/06 / springboot / chapter-thirty-two /