[enjoy learning Netflix] 3. Apache Commons Configuration2.x new event monitoring mechanism

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.

Published 298 original articles, won praise 456, visited 390000+
His message board follow

Keywords: Apache Spring Java hot update

Added by brendan2b on Tue, 18 Feb 2020 11:48:00 +0200