Spring Master's Road 14 - Explain in simple terms: Application of SPI mechanism in JDK and Spring Boot

1. SPI Interpretation: What is SPI?

  SPI( Service Provider Interface) is a service discovery mechanism that allows third-party providers to provide implementations or extensions to the core library or main framework. This design allows core libraries/frameworks to enhance functionality through third-party implementations without modifying their own code.

  1. JDK native SPI :
  • Definition and discovery : JDKIt SPImainly META-INF/services/specifies which classes implement a given service interface by placing specific files in the directory. The name of these files should be the fully qualified name of the interface and the contents should be the fully qualified class name that implements the interface.

  • Loading mechanism : The class loader mechanism ServiceLoaderused by the class loads and instantiates service providers from the directory. For example, an implemented instance iterator is returned .JavaMETA-INF/services/ServiceLoader.load(MyServiceInterface.class)MyServiceInterface

  • Disadvantages : JDKThe native one will initialize a new instance SPIevery time it is loaded, does not implement class caching, and does not consider advanced features such as singletons.ServiceLoader

  1. Spring's SPI :
  • More flexible : SpringIt SPIis not just service discovery, it provides a complete plug-in mechanism. For example, you can Springdefine new ones PropertySource, ApplicationContextInitializeretc.

  • Integrated with IoC : Unlike JDKIoC SPI, IoC is integrated with its Spring( IoC ) container, allowing full functionality such as dependency injection to be leveraged in the implementation .SPIIoCInversion of ControlSPISpring

  • Condition matching : Provides a condition-based matching mechanism, which allows only specific implementations Springto be loaded under certain conditions . For example, you can choose which database driver to load based on the current running environment.SPI

  • Configuration : SpringAllows configuration spring.factoriesin a directory through files , this is very similar to , but it provides more functionality and flexibility.META-INFJDKSPI

Give an analogy example:

  Imagine we are building a television, SPIlike a socket on the television USB. This socket can be plugged into various devices (such as USB flash drives, game controllers, TV sticks, etc.), but we don't care about the inner workings of these devices. In this way, only a standard interface needs to be provided, and other companies (such as USB disk manufacturers) can provide implementations for this interface. This way, the TV can use a variety of new devices without changing its own internal code, and device manufacturers can make compatible devices for various TV sets.

  In short, SPIit is a design pattern that separates interface definition and implementation. It encourages third parties to provide plug-ins or implementations for a core product or framework, so that the core product can easily extend its functionality.

2. Application examples of SPI in JDK

  In Javathe ecosystem, SPIit is a core concept that allows developers to provide extensions and alternative implementations without having to change the core library or application. An example is given below to illustrate.

All codes and steps are as follows:

Step 1 : Define a service interface, file name:MessageService.java

package com.example.demo.service;

public interface MessageService {
    
    
    String getMessage();
}

Step 2 : Provide implementation for the service interface. Two simple implementation classes will be provided here.

HelloMessageService.java

package com.example.demo.service;

public class HelloMessageService implements MessageService {
    
    
    @Override
    public String getMessage() {
    
    
        return "Hello from HelloMessageService!";
    }
}

HiMessageService.java

package com.example.demo.service;

public class HiMessageService implements MessageService {
    
    
    @Override
    public String getMessage() {
    
    
        return "Hi from HiMessageService!";
    }
}

These implementations are like different makes or models of USB flash drives or other USBdevices. Each device has its own functions and features, but all adhere to the same USBstandards.

Step 3 : Register a service provider

src/main/resources/Create a META-INF/services/folder named   under the resources directory (usually ). In this folder, create a com.example.demo.service.MessageServicefile called (this is the fully qualified name of our interface ). This file does not have any file extension, so do not add .txtsuch a suffix. The contents of the file should be the fully qualified names of our two implementation classes, one on each line:

com.example.demo.service.HelloMessageService
com.example.demo.service.HiMessageService

Insert image description here

  META-INF/services/Is a specific directory that is agreed upon in the Java SPI( ) mechanism. Service Provider InterfaceIt is not chosen arbitrarily but SPIis clearly defined in the specification. Therefore, when using JDKthe ServiceLoaderclass to load a service provider, it will specifically look for files in this path.

  Please make sure that the file has only one name per line and that there are no extra spaces or hidden characters and that the file uses UTF-8the encoding.

Step 4 : ServiceLoaderLoad and consume services using

package com.example.demo;

import com.example.demo.service.MessageService;

import java.util.ServiceLoader;

public class DemoApplication {
    
    

    public static void main(String[] args) {
    
    
        ServiceLoader<MessageService> loaders = ServiceLoader.load(MessageService.class);

        for (MessageService service : loaders) {
    
    
            System.out.println(service.getMessage());
        }
    }
}

The running results are as follows:

Insert image description here

  This shows that the two implementations we provided ServiceLoaderfor the interface were successfully loaded , and that we can extend our service by adding more implementation classes and updating files without modifying the class's code .MessageServiceMainMETA-INF/services/com.example.MessageService

Imagine buying a high-end smart TV. This TV has one or more HDMIports on it. This is how it connects to external devices.

  1. Define the service interface : This is like a standard that defines HDMIa port for a TV. In the code above, MessageServicethe interface is the " HDMIport" that defines how to communicate with external devices.

  2. Providing implementations for service interfaces : This is similar to manufacturers HDMIproducing interfaces for various devices, such as game consoles, Blu-ray players or streaming sticks. In code, HelloMessageServiceand HiMessageServiceare these " HDMIdevices". Each device/implementation has its own unique output, but all follow a unified HDMIstandard ( MessageServiceinterface).

  3. Registered Service Provider : When we purchase a HDMIdevice, it is usually clearly marked "Suitable for" on the box HDMI. This is like a logo telling the user that it can be connected to any HDMITV with an interface. In SPIthe example, META-INF/services/the directory and the files within it act like this "label" that tells JDKwhich classes are MessageServiceimplemented.

  4. Use ServiceLoader to load and use services : When a HDMIdevice is plugged into the TV and switched to the correct input channel, the TV will display the device's content. Similarly, in this step of the code, ServiceLoaderlike the TV's input selection function, is able to discover and use all connected HDMIdevices (i.e. MessageServiceall implementations of ).

3. Application of SPI in Spring framework

  SpringThe official mentioned the concept of SPI( Service Provider Interface) many times in its documentation and source code. However, when we say " Springof SPI", we usually refer to Springthe set of extensible interfaces and abstract classes provided by the framework to developers, and developers can implement their own versions based on these interfaces and abstract classes.

In Spring, SPIthe concept and the file mechanism Spring Bootused spring.factoriesare not exactly the same, but they all embody the ideas of pluggability and extensibility.

  1. Spring's SPI :
  • SpringThe core framework provides many interfaces and abstract classes, such as BeanPostProcessor, PropertySource, ApplicationContextInitializeretc., which can be regarded Springas SPI. Developers can implement these interfaces to extend Springthe functionality. These interfaces allow developers Springto intervene at different stages of the container's life cycle to implement their own logic.
  1. Spring Boot’s spring.factories mechanism :
  • spring.factoriesIs Spring Boota feature that allows developers to customize automatic configuration. Through spring.factoriesfiles, developers can define their own auto-configuration classes, which Spring Bootwill be automatically loaded at startup.

  • In this case, SpringFactoriesLoaderthe use, specifically via spring.factoriesa file to load and instantiate a defined class, can be seen as an SPIimplementation-specific approach, but it is specific to Spring Boot.

3.1 SPI ideas in the traditional Spring framework

  In the traditional Springframework, although "SPI"the term named is not used directly, the core idea still exists. SpringProvides multiple extension points, the most representative of which is BeanPostProcessor. MessageServiceIn this section, we will explore how to take advantage of the ideas embodied by extension points through a simple interface Springand BeanPostProcessorits implementation SPI.

Two simple implementation classes are provided.

HelloMessageService.java

package com.example.demo.service;

public class HelloMessageService implements MessageService {
    
    
    @Override
    public String getMessage() {
    
    
        return "Hello from HelloMessageService!";
    }
}

HiMessageService.java

package com.example.demo.service;

public class HiMessageService implements MessageService {
    
    
    @Override
    public String getMessage() {
    
    
        return "Hi from HiMessageService!";
    }
}

definitionBeanPostProcessor

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MessageServicePostProcessor implements BeanPostProcessor {
    
    
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        if(bean instanceof MessageService) {
    
    
            return new MessageService() {
    
    
                @Override
                public String getMessage() {
    
    
                    return ((MessageService) bean).getMessage() + " [Processed by Spring SPI]";
                }
            };
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
        return bean;
    }
}

Modify Springconfiguration

Will MessageServicePostProcessorbe added to Springthe configuration:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MessageServiceConfig {
    
    
    
    @Bean
    public MessageService helloMessageService() {
    
    
        return new HelloMessageService();
    }

    @Bean
    public MessageService hiMessageService() {
    
    
        return new HiMessageService();
    }
    
    @Bean
    public MessageServicePostProcessor messageServicePostProcessor() {
    
    
        return new MessageServicePostProcessor();
    }
}

execute program

Using the example class provided earlier DemoApplication:

package com.example.demo;

import com.example.demo.configuration.MessageServiceConfig;
import com.example.demo.service.MessageService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class DemoApplication {
    
    

    public static void main(String[] args) {
    
    
        ApplicationContext context = new AnnotationConfigApplicationContext(MessageServiceConfig.class);
        MessageService helloMessageService = context.getBean("helloMessageService", MessageService.class);
        MessageService hiMessageService = context.getBean("hiMessageService", MessageService.class);

        System.out.println(helloMessageService.getMessage());
        System.out.println(hiMessageService.getMessage());
    }
}

operation result:

Insert image description here

  Now, each MessageServiceimplementation is BeanPostProcessorprocessed, adding additional messages “[Processed by Spring SPI]”. This demonstrates the Springconcept SPIof BeanPostProcessorextending or modifying Springa container bean.

  Someone may have noticed the red warning here. As mentioned before BeanPostProcessor, this situation will occur when BeanPostProcessorone or more of them are processed. BeanPostProcessorSimply put, some cannot handle early initialization because BeanPostProcessorthey need to be initialized before others , including configuration classes and others . The solution is not to initialize it in the configuration class, delete it in the configuration class, and then add annotations.beanBeanPostProcessorbeanBeanPostProcessorMessageServicePostProcessorMessageServicePostProcessor@Component

Analogy to the TV example at the beginning of the article:

  1. TV and USB Port : In this new example, TV is still the core Springapplication, specifically DemoApplicationthe class. This core application needs to MessageServiceget and print a message from some service (ie.

  2. USB socket : As before, MessageServicethe interface is this " USBsocket". It provides a standardized interface, that is, getMessage()a method, for TVs, but does not specify how to implement it.

  3. Equipment Manufacturers and Their Products : Here we have two types of equipment manufacturers or third party providers: HelloMessageServiceand HiMessageService. They provide different devices or implementations for " USBsockets" (i.e. interfaces). MessageServiceOne shows “Hello from HelloMessageService!”, the other shows “Hi from HiMessageService!”.

  4. BeanPostProcessor : This is a special "magic box" that can be thought of as a smart device that can intercept and modify the content displayed on the TV. When you plug in USBa device (i.e. MessageServicean implementation of ) and try to get messages from it, this "magic box" steps in and adds for each message “[Processed by Spring SPI]”.

  5. Spring context configuration : This is still the instruction manual of the TV, but now it uses Javaa configuration method based on classes, that is, MessageServiceConfigclasses. This "instruction manual" instructs Springthe container on how to create and manage MessageServiceinstances, and also instructs it on how to use "magic boxes" (i.e. MessageServicePostProcessor) to process messages.

  Overall, this new example provides a more dynamic scenario than the previous example, where the Springextension BeanPostProcessorpoints allow us to intercept and modify beanthe behavior, like a smart device that can intervene and change the content displayed on the TV.

3.2 SPI idea in Spring Boot

  Spring BootThere is a SPIsimilar mechanism to Javathe standard , but it's not exactly equivalent SPI.

  Spring BootThe automatic configuration mechanism mainly relies on spring.factoriesfiles. This file can jarexist in multiple locations, and Spring Bootall visible spring.factoriesfiles will be loaded. We can declare a series of automatic configuration classes in this file, so that when certain conditions are met, these configuration classes will be automatically applied Spring Boot.

A good example of the idea is shown next Spring SPI, but it is Spring Bootclosely related.

Define interface

package com.example.demo.service;

public interface MessageService {
    
    
    String getMessage();
}

Two simple implementation classes will be provided here.

HelloMessageService.java

package com.example.demo.service;

public class HelloMessageService implements MessageService {
    
    
    @Override
    public String getMessage() {
    
    
        return "Hello from HelloMessageService!";
    }
}

HiMessageService.java

package com.example.demo.service;

public class HiMessageService implements MessageService {
    
    
    @Override
    public String getMessage() {
    
    
        return "Hi from HiMessageService!";
    }
}

Registration service

resources/META-INFCreate a file named under spring.factories. In this file, MessageServiceimplementation classes can be registered.

com.example.demo.service.MessageService=com.example.demo.service.HelloMessageService,com.example.demo.service.HiMessageService

Insert image description here

  Note that this com.example.demo.service.MessageServiceis the full path of the interface, com.example.demo.service.HelloMessageService,com.example.demo.service.HiMessageServicebut the full path of the implementation class. If there are multiple implementation classes, they should be separated by commas.

  spring.factoriesThere must be no line breaks between entry keys and values ​​in the file, i.e. key=valuethe structure of the form must start on the same line. However, if there are multiple values ​​that need to be listed (such as multiple implementation classes), and the values ​​are comma separated, you can use backslash ( ) \to break the line. spring.factoriesThe name is conventional. If you try to use a different file name, then Spring Bootthe autoconfiguration mechanism will not recognize it.

Here spring.factoriesit can be written as

com.example.demo.service.MessageService=com.example.demo.service.HelloMessageService,\
  com.example.demo.service.HiMessageService

Entering directly after the comma IDEAwill automatically complete the backslash, ensuring that there is no line break between the key and the value.

Use SpringFactoriesLoaderto load services

package com.example.demo;

import com.example.demo.service.MessageService;
import org.springframework.core.io.support.SpringFactoriesLoader;

import java.util.List;

public class DemoApplication {
    
    

    public static void main(String[] args) {
    
    
        List<MessageService> services = SpringFactoriesLoader.loadFactories(MessageService.class, null);
        for (MessageService service : services) {
    
    
            System.out.println(service.getMessage());
        }
    }
}

SpringFactoriesLoader.loadFactoriesThe second parameter is the class loader, here we use the default class loader, so pass it null.

operation result:

Insert image description here

  This approach takes advantage of the API Spring, SpringFactoriesLoaderwhich allows developers to provide multiple implementations of an interface and spring.factoriesregister them through files. This is very similar to the idea JDKof SPI​​​​but differs in the implementation details. This is also Spring Bootthe basis for automatic configuration. It will look for various spring.factoriesfiles and initialize and configure them based on the classes defined in them bean.

Let’s continue using the TV example to explain:

  1. TV : This is our Springapp, like DemoApplication. A TV is a device that views different sources or channels, and our application is designed to run and use different service implementations.

  2. USB socket : This represents our MessageServiceinterface. USBA socket is a standard interface that allows the connection of various devices, just as MessageServicean interface allows multiple implementations.

  3. USB device (such as USB flash drive or mobile hard disk) : This represents our service implementation, such as HelloMessageServiceand HiMessageService. Each USBdevice has specific content or functionality when plugged into the TV, just like each of our service implementations returns a different message.

  4. TV's USB device directory : This is spring.factoriesthe file. When we USBplug a device into the TV, the TV checks the device's information or content, and spring.factoriesthe file tells Spring Bootwhich service implementations are available, just like the TV knows which USBdevices are plugged in.

  5. TV’s USB scanning function : That’s it SpringFactoriesLoader. When we want to view USBcontent from the TV, the TV scans and displays the content. Likewise, when DemoApplicationrun, the service implementations listed in the file SpringFactoriesLoaderare found and loaded .spring.factories

Simplified explanation:

  • When USBa device is plugged into a TV, the TV is expected to recognize and display the device's content.

  • In our case, USBthe content of the device is MessageServicethe message returned from the implementation class.

  • spring.factoriesThe file is like the TV's built-in directory, telling the TV which USBdevices are known and available for use.

  • When our DemoApplication(television) is running, it uses SpringFactoriesLoader( USBscan function) to check which services ( USBdevices) are available and outputs the appropriate message (display USBcontent).

  Summary: In this Spring Bootexample SPI, we show Springhow the core application automatically recognizes and uses the registered implementation in the file, similar to spring.factorieshow a television automatically recognizes and uses all plugged-in devices.USB

4. Application of SPI in JDBC driver loading

  The database driver SPIis mainly reflected in JDBCthe automatic discovery mechanism of the driver. JDBC 4.0Introduced a feature that allows drivers to automatically register to DriverManager. This is achieved by Javausing . There will be a file in SPIthe driver package , which contains the full class name of the driver's implementation class. In this way, when there is a driver file in the classpath , the application can automatically discover and load the driver without explicitly loading the driver class.jarMETA-INF/services/java.sql.DriverDriverJDBCjarJavaJDBC

  This means that any database vendor can write its own JDBCdriver and as long as it adheres to JDBCthe driver's specifications SPI, it can be used by any application that JDBCuses it.Java

When we use to DriverManager.getConnection()obtain a database connection, SPIthe mechanism behind it is used to load the appropriate driver.

Here's SPIexactly how the mechanism works:

  1. Define service interface :

Here, the interface is already Javadefined by the platform, ie java.sql.Driver.

  1. Provide an implementation for the interface :

Major database vendors (such as Oracle, MySQL, , PostgreSQLetc.) provide JDBCdrivers for their databases, and they all implement java.sql.Driverthe interface. For example, MySQLthe driver has a class similar to the following:

public class com.mysql.cj.jdbc.Driver implements java.sql.Driver {
    
    
    // 实现接口方法...
}

Directly above the picture:

Insert image description here

  1. Register service provider :

For MySQLthe driver, you can find a file named in the directory JARof its files . The content of the file is as follows:META-INF/servicesjava.sql.Driver

com.mysql.cj.jdbc.Driver

Directly above the picture:

Insert image description here

When you see this, do you find that it is the same as the example 2given in Section 1 JDK SPI? Experience it.

  1. Use SPI to load and use services :

  When we call DriverManager.getConnection(jdbcUrl, username, password), all registered implementations DriverManagerwill be found using . It then tries each driver until it finds one that can handle the given one .ServiceLoaderjava.sql.DriverjdbcUrl

Here is a simple example showing how to get JDBC SPIa database connection using:

import java.sql.Connection;
import java.sql.DriverManager;

public class JdbcExample {
    
    
    public static void main(String[] args) {
    
    
        String jdbcUrl = "jdbc:mysql://localhost:3306/mydatabase";
        String username = "root";
        String password = "password";

        try {
    
    
            Connection connection = DriverManager.getConnection(jdbcUrl, username, password);
            System.out.println("Connected to the database!");
            connection.close();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
}

  In the above code, we do not explicitly specify which JDBCdriver to use, as DriverManagerthe appropriate driver is automatically selected for us.

  This modular and plug-in mechanism makes it easy to switch drivers for different databases by simply changing JDBC URLand ensuring that the corresponding driver JARis on the classpath.

  In Spring Boot, developers typically do not interact directly with JDBCthe SPImechanism to obtain a database connection. Spring BootThe automatic configuration mechanism hides many low-level details, making configuring and using the database easier.

Generally, database connection information is configured in application.propertiesor .application.yml

For example:

spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

  In the above steps, the automatic configuration mechanism will initialize and configure the object Spring Bootbased on the provided dependencies and configuration information . This object manages the database connection. DataSourceIn fact, when adding JDBCa driver dependency, the mechanism (applied in the specification) Spring Bootwill be used JDKto find and load the corresponding database driver. Although developers do not directly interact with it , they do use mechanisms behind the scenes to obtain database connections.SPIJDBCJDKSPISpring BootJDK SPI

5. How to understand SPI ideas through Spring Boot automatic configuration

  This mechanism is somewhat similar Javato SPI, in that it allows third-party libraries to provide some default configuration. But it is more powerful and flexible than Java, SPIbecause Spring Bootit provides a large number of annotations (such as @ConditionalOnClass, @ConditionalOnProperty, @ConditionalOnMissingBeanetc.) to control whether the auto-configuration class should be loaded and applied.

  Overall, Spring Bootthe spring.factoriesmechanisms of Javaand SPIare conceptually similar, but they differ in implementation details and purpose.

Let's create a simplified practical example, assuming we want to create automatic configurations for different messaging services such as SMSand .Email

MessageService interface :

package com.example.demo.service;

public interface MessageService {
    
    
    void send(String message);
}

SMS service implementation :

package com.example.demo.service.impl;

import com.example.demo.service.MessageService;

public class SmsService implements MessageService {
    
    
    @Override
    public void send(String message) {
    
    
        System.out.println("Sending SMS: " + message);
    }
}

Email service implementation :

package com.example.demo.service.impl;

import com.example.demo.service.MessageService;

public class EmailService implements MessageService {
    
    
    @Override
    public void send(String message) {
    
    
        System.out.println("Sending Email: " + message);
    }
}

Automatic configuration class :

package com.example.demo.configuration;

import com.example.demo.service.EmailService;
import com.example.demo.service.MessageService;
import com.example.demo.service.SmsService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MessageAutoConfiguration {
    
    

    @Bean
    @ConditionalOnProperty(name = "message.type", havingValue = "sms")
    public MessageService smsService() {
    
    
        return new SmsService();
    }

    @Bean
    @ConditionalOnProperty(name = "message.type", havingValue = "email")
    public MessageService emailService() {
    
    
        return new EmailService();
    }
}

  This class provides two conditionals beans(components), namely SmsServiceand EmailService. beansThe creation of these depends on application.propertiesspecific property values ​​in the file.

  • @ConditionalOnProperty(name = “message.type”, havingValue = “sms”)

This condition is when   the value of the property defined in application.propertiesor is . At this point, the method will be called, creating a .application.ymlmessage.typesmstruesmsService()SmsServicebean

  • @ConditionalOnProperty(name = “message.type”, havingValue = “email”)

This condition is when   the value of the property defined in application.propertiesor is . At this point, the method will be called, creating a .application.ymlmessage.typeemailtrueemailService()EmailServicebean

spring.factories file :

src/main/resources/META-INFCreate a file in the directory with spring.factoriesthe following content:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.demo.configuration.MessageAutoConfiguration

application.properties file :

message.type=sms

MessageTester component :

package com.example.demo;

import com.example.demo.service.MessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class MessageTester {
    
    

    @Autowired
    private MessageService messageService;

    @PostConstruct
    public void init() {
    
    
        messageService.send("Hello World");
    }
}

DemoApplication main program :

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(DemoApplication.class, args);
    }
}

operation result:

Insert image description here

  In the above example, we created an MessageServiceinterface and two implementations ( SmsServiceand EmailService). We then created an autoconfiguration class that contained two beandefinitions that were conditionally created beanbased on the property values ​​in . application.propertiesIn spring.factoriesthe file, we declare this autoconfiguration class so that Spring Bootit can be automatically loaded on startup.

Here, continue to use the example of a television to sublimate our understanding.

TV analogy

  1. General concept :
  • Suppose TV ( TV) is an Javaapplication.

  • Various slots of the TV, such as HDMI, USB, , VGAetc., can be regarded as interfaces in the application SPI.

  • Devices plugged into these slots (such as DVDplayers, game consoles, USBdrives, etc.) can be considered SPIimplementations.

  1. Java SPI :
  • When we buy a TV, we don't know what kind of device will be connected to it. It may be DVDa player or a game console.

  • However, as long as the devices adhere to the standard for the slot (i.e., HDMIa standard), you can plug it into your TV and have it work.

  • This is like Javaa SPImechanism: in order to allow multiple vendors to provide implementations, Javaan interface is defined, and vendors provide specific implementations.

  1. Spring Boot automatic configuration :
  • Now, imagine a modern smart TV. When a device is plugged in, the TV not only recognizes it, but may also automatically adjust settings based on the type of device connected, such as selecting the correct input source, optimizing image quality, and more.

  • This is like Spring Bootautoconfiguration: when Spring Bootthe app starts, it checks for classpaththe libraries on it and automatically configures the app based on the libraries that are present.

  • The automatic settings of the TV can be compared to Spring Bootthe spring.factoriesand various @Conditional... Notes. They determine which configuration is performed under what conditions.

  1. Scalability :
  • If a TV manufacturer wants to develop a TV for a new type of slot or connection technology, it can easily add the new slot to its TV models.

  • Likewise, Spring Bootif you want to add new features or libraries to your application, just add the relevant dependencies and Spring Bootthese new features will be automatically recognized and configured.

  Using this analogy, the TV's slot and auto-configuration features provide us with an intuitive way to understand how the Javamechanisms SPIand Spring Bootauto-configuration work, and how they provide convenience to application developers.

6. SPI (Service Provider Interface) Summary

  SPI, that is, the service provider interface, is a specific design pattern. It allows a framework or core library to provide a predefined interface to third-party developers, allowing them to provide custom implementations or extensions to the framework.

Core goals :

  1. Decoupling: SPIThe mechanism keeps the core of the framework decoupled from its extensions, so that the core code does not depend on the specific implementation.

  2. Dynamic loading: The system is able to dynamically discover and load the required implementation through specific mechanisms (such as Java) .ServiceLoader

  3. Flexibility: Framework users can choose, replace or add new implementations according to their needs without modifying the core code.
    Pluggable: Services or implementations provided by third parties can be easily added to or removed from the system without changing the existing code structure.

Value :

  • Provides users of the framework or library with more customization options and flexibility.

  • Allowing the core parts of the framework to remain stable while being able to accommodate new features and extensions.

SPI and "opening and closing principle" :

  The "open-closed principle" advocates that software entities should be open to extension but closed to modification. That is, adding new functions through extension without changing the existing code.

How does SPI embody the "open-close principle" :

  1. Open for extension: SPIProvides a standardized way for third-party developers to provide new implementations or functionality for existing systems.

  2. Closed to modification: When new functionality or features are added, the code of the original framework or library does not need to be modified.

  3. Independent development: The framework and its SPIimplementation can evolve and develop independently without affecting each other.

  In short, SPIit is an effective way to make a software framework or library more modular, extensible and maintainable. By following the "open-close principle", SPIthe stability and flexibility of the system are ensured to meet changing business needs.


Welcome to the one-click triple connection~

If you have any questions, please leave a message, let's discuss and learn together

----------------------Talk is cheap, show me the code----- ------------------

Guess you like

Origin blog.csdn.net/qq_34115899/article/details/132475084