Writing good code is personal accomplishment, not the requirement of the boss, not to show colleagues
- > return to the column directory
Code download address: https://github.com/f641385712/netflix-learning
Catalog
Preface
The previous article focuses on the use and principle of Apache commons configuration 1. X. as a technology that has been stopped in 2013, it is not necessary to learn it again. But because Netflix still relies on it, it becomes necessary.
However, as the current mainstream version of 2.x, it can't be ignored. It almost completely rewrites 1.x code, so it is naturally not downward compatible, and because package names are different, 2.x and 1.x can coexist.
Because in practice, it's 100% recommended to use version 2.x, so it's more realistic to spend some time and energy to understand it. This article will take the event listening mechanism as the starting point to introduce the new event listening mechanism of Apache Commons Configuration2.x.
text
2.x completely overthrows the 1.x event monitoring mechanism and redesigns a new API. Maybe it has learned Spring, which makes it quite similar to Spring's event mechanism, so it will be more friendly for readers to understand.
Event
Inherited from the JDK standard event java.util.EventObject. It is the base class of all events, the same as Spring's org.springframework.context.ApplicationEvent.
public class Event extends EventObject { // root event. So event types all inherit directly / indirectly from it // If you're listening to this type of event, it's listening to all the events public static final EventType<Event> ANY = new EventType<>(null, "ANY"); // The only constructor source and EventType are required to determine the event source and type you send // For example, adding person. Person is the event source and new is the event type public Event(final Object source, final EventType<? extends Event> evType) { ... } }
The following events are built in:
ConfigurationEvent
No explanation.
public class ConfigurationEvent extends Event { // The built-in event types of this event source are public public static final EventType<ConfigurationEvent> ANY = new EventType<>(Event.ANY, "CONFIGURATION_UPDATE"); public static final EventType<ConfigurationEvent> ADD_PROPERTY = new EventType<>(ANY, "ADD_PROPERTY"); ... // Add, delete, change and many other operations private final String propertyName; private final Object propertyValue; private final boolean beforeUpdate; ... }
ConfigurationErrorEvent
It no longer inherits from ConfigurationEvent like 1.x, but directly from Event.
public class ConfigurationEvent extends Event { public static final EventType<ConfigurationEvent> ANY = new EventType<>(Event.ANY, "CONFIGURATION_UPDATE"); public static final EventType<ConfigurationEvent> ADD_PROPERTY = new EventType<>(ANY, "ADD_PROPERTY"); ... // Omit other event types private final String propertyName; private final Object propertyValue; private final boolean beforeUpdate; ... }
ReloadingEvent
Reloading: reloading is a very important concept in Commons Configuration, which generally serves hot update, hot load and other important functions.
This event is quite special. You can focus on it.
public class ReloadingEvent extends Event { // Note: it has only one event type, and there are sub types public static final EventType<ReloadingEvent> ANY = new EventType<>(Event.ANY, "RELOAD"); // Additional data sent during reloading, no null able private final Object data; // Small details: we can draw conclusions from this method // The event source sending this event: must be reloading controller public ReloadingController getController() { return (ReloadingController) getSource(); } }
The event source that sent this event: must be reloading controller.
ConfigurationBuilderEvent
It is also a very special event that will be emitted in the configuration builder.
public class ConfigurationBuilderEvent extends Event { public static final EventType<ConfigurationBuilderEvent> ANY = new EventType<>(Event.ANY, "BUILDER"); // This event is issued when the basicconfigurationbuilder? Resetresult() method is called public static final EventType<ConfigurationBuilderEvent> RESET = new EventType<>(ANY, "RESET"); // Configurationbuilder ා getconfiguration() is called, when getting. Send this event // Please note at that time: This is a request initiated, but it is not necessarily a success (an exception may be thrown in the middle) public static final EventType<ConfigurationBuilderEvent> CONFIGURATION_REQUEST = new EventType<>(ANY, "CONFIGURATION_REQUEST"); // Similarly, this event source must be 'ConfigurationBuilder'` @Override public ConfigurationBuilder<?> getSource() { return (ConfigurationBuilder<?>) super.getSource(); } }
Its event source must be a ConfigurationBuilder instance.
ConfigurationBuilderResultCreatedEvent
It extends the parent class ConfigurationBuilderEvent by adding the event type Result ﹐ created, indicating the event after the Result is created successfully (note the difference between the configuration ﹐ request of the parent class).
The event source also provides access to Configuration, because sending this time can definitely confirm that the Configuration instance has been created successfully~~~
public class ConfigurationBuilderResultCreatedEvent extends ConfigurationBuilderEvent { // It indicates the event sent after the Result gets * * successfully * * public static final EventType<ConfigurationBuilderResultCreatedEvent> RESULT_CREATED = new EventType<>(ANY, "RESULT_CREATED"); // Provide access to the configuration object. After all, sending this event means the creation is successful~ // Configuration is the majority of cases private final ImmutableConfiguration configuration; }
EventType
Event type. Each type can have a parent type to which it belongs, as well as a name. Spring does not propose the concept of time type, but uses Class type to distinguish. I think Commons Configuration has more advantages~
public class EventType<T extends Event> implements Serializable { private final EventType<? super T> superType; private final String name; ... // Omit constructor // Get all the parent types of the type (recursively called to the top level) public static Set<EventType<?>> fetchSuperEventTypes(final EventType<?> eventType) { ... } // Whether the derived type is a subtype of the baseType (recursive to compare) public static boolean isInstanceOf(final EventType<?> derivedType, final EventType<?> baseType) { ... } }
In most cases, you don't need to customize your own EventType, just use it out of the box.
EventListener
Listener, listening to the specified event (type), which is a functional interface. Similar to org.springframework.context.ApplicationListener, it is also a functional interface. The interface method is onApplicationEvent(E event).
public interface EventListener<T extends Event> { void onEvent(T event); }
List several built-in common implementations:
AutoSaveListener
Realize the listener class configuration based on the automatic saving mechanism of file, and it also implements FileHandlerListener so that the file can be saved automatically. Its access right is default, and it cannot be used directly by external users.
ReloadingBuilderSupportListener
An internal help class for adding Reloading support to any Configuration object: this support includes automatic resetResult() and resetreloading state(), so it is necessary.
// Note: it monitors all events~~~~ final class ReloadingBuilderSupportListener implements EventListener<Event> { private final BasicConfigurationBuilder<?> builder; private final ReloadingController reloadingController; ... // Omit constructor assignment // When listening to the event "result" created, that is, after Configuration is successfully created and return is returned, reset its reloading state // That is to say, ensure that the acquired object can still be hot loaded // If it is another event, resetresult() - > result = null and a RESET event is issued @Override public void onEvent(final Event event) { if (ConfigurationBuilderResultCreatedEvent.RESULT_CREATED.equals(event.getEventType())) { reloadingController.resetReloadingState(); } else { builder.resetResult(); } } // =======It also provides a static method for you to bind====== public static ReloadingBuilderSupportListener connect( final BasicConfigurationBuilder<?> configBuilder, final ReloadingController controller) { final ReloadingBuilderSupportListener listener = new ReloadingBuilderSupportListener(configBuilder, controller); // Bind the time to reloading controller // Description: reloading controller is an EventSource, so you can listen to it // And it can issue reloadevent events. Therefore, it is found that when reloading event is issued, the result operation of this listener will be triggered controller.addEventListener(ReloadingEvent.ANY, listener); // Monitor the Result created event for the builder. When the Result created arrives at the listener, the Result will be cleared configBuilder.installEventListener( ConfigurationBuilderResultCreatedEvent.RESULT_CREATED, listener); return listener; } }
The only way the listener can be exposed to the outside world is: ReloadingBuilderSupportListener.connect(this, controller); which is used when creating ReloadingController in BasicConfigurationBuilder.
EventListenerRegistrationData
Registration: registration, registration. Data class containing event listener registration information
// Provide data for registering listeners public final class EventListenerRegistrationData<T extends Event> { private final EventType<T> eventType; private final EventListener<? super T> listener; }
EventListenerList
This is relatively simple. The internal management maintains a bunch of listeners, and provides methods such as registration, removal, emptying, acquisition, etc.
public class EventListenerList { private final List<EventListenerRegistrationData<?>> listeners; // It can be seen that the addition, deletion and modification of it are thread safe public EventListenerList() { listeners = new CopyOnWriteArrayList<>(); } ... //addEventListener/removeEventListener/fire/getEventListeners // Get all the listeners listening to this event type (and all its sub event types) public <T extends Event> List<EventListenerRegistrationData<? extends T>> getRegistrationsForSuperType(EventType<T> eventType) { ... } ... }
Use example
Introduced so many, from the API level should be able to deeply feel that it and 1.x design are totally different, on the contrary, it is almost the same as Spring design.
Is it friendly at the use level? Please see the following simple case:
@Test public void fun100() throws ConfigurationException { Configurations configs = new Configurations(); PropertiesConfiguration config = configs.properties("1.properties"); // Listen for add property add property events config.addEventListener(ConfigurationEvent.ADD_PROPERTY, event -> { if (!event.isBeforeUpdate()) { System.out.printf("Property added successfully:%s = %s", event.getPropertyName(), event.getPropertyValue()); } }); config.addProperty("name","YourBatman"); }
Console printing:
Successfully added attribute: name = YourBatman
It can be seen that although the core API has changed a lot, it has not changed much at the most basic level of use and is relatively user-friendly. But then again, there are a lot of switching and understanding costs.
summary
This is about the event monitoring mechanism of Apache commons configuration 2.x. for example, we can see that the change of 2.x compared with 1.x is very big, which is the most important reason why the Apache team chose to rename instead of upgrading directly on 1.x.
Meet each other by click, the changes of each part of 2.x are not small, so it will not be smooth to move from 1.x knowledge to 2.x, and even need to be relearned. This series will gradually show it to you, so that you can freely use Apache commons configuration 2.x version in your work.
statement
It's not easy to create and code. Thank you for your praise, collection and attention. Sharing this article with your circle of friends is allowed, but no plagiarism is allowed. You can also [scan the code on the left] to join my Java senior engineer and architect series of family learning and communication.