This is the 7th day of my participation in the August Text Challenge.More challenges in August

Usage of ServiceLoader

The Java SE 6 platform provides a new API to help find, load, and consume service providers. In fact, the java.util.ServiceLoader class has been around since version 1.3 of the Java platform, but it only became a public API in Java SE 6.

1. What is

The ServiceLoader class is used to search for service providers in the application’s classPath (classPath) or in the runtime environment’s extended directory (java.ext.dirs). It loads these services and gives them to the program to use, and when new extensions are added, the ServiceLoader can find them and, knowing the interface, find and use various implementations of that interface.

2. How to use it

According to the official documentation, it is mainly used to load a series of service providers. In addition, the ServiceLoader can load the specified service Provider through the service Provider configuration file. After reading this paragraph, or more meng, start the example. We define two MessageService interfaces as follows:

public interface MessageService {
    String getMessage(a);
}
Copy the code

RawMessage is implemented as follows:

package com.test.raw;
import com.test.service.MessageService;
public class RawMessage implements MessageService {
    public String getMessage(a) {
        return "Raw message"; }}Copy the code

FormattedMessage is implemented as follows:

package com.test.format;

import com.test.service.MessageService;

public class FormattedMessage implements MessageService {
    public String getMessage(a) {
        return "Formatted message"; }}Copy the code

Under the original code directory to create a meta-inf/services directory, and create a com. Test. Service. MessageService file. The filename must be the same as the full name of the MessageService class we defined earlier, which reads as follows:

com.test.raw.RawMessage
com.test.format.FormattedMessage
Copy the code

Load all services and use:

public class MessageConsumer {
	public static void main(String[] args) {
		ServiceLoader<MessageService> serviceLoader = ServiceLoader.load(MessageService.class);
		for(MessageService service : serviceLoader) { System.out.println(service.getMessage()); }}}Copy the code

Running results:

Raw message
Formatted message
Copy the code

Does it look like a simple implementation of dependency injection? We can provide specific classes to the user through configuration files. Of course, there is a specific restriction for the ServiceLoader, which is that the implementation classes we provide must provide a no-argument constructor or the ServiceLoader will report an error.

Examples used in projects

 try{ FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator().next(); . }catch (BundleException e) {
        ...
     }
Copy the code

3. Some limitations

The ServiceLoader API is useful, but it has some limitations.

  • You cannot inherit ServiceLoader, so you cannot modify its behavior.

You can use custom ClassLoader subclasses to change how classes are found, but you cannot extend the ServiceLoader itself.

  • The current ServiceLoader class does not tell the application when a new provider is available at runtime. At the same time, you cannot add change listeners to the loader to find out if a new provider has been placed in an application-specific extension directory.