使用SPI机制前后的代码变化

  • 加载MySQL对JDBC的Driver接口实现
    在未使用SPI机制之前,使用JDBC操作数据库的时候,一般会写如下的代码:

    // 通过这行代码手动加载MySql对Driver接口的实现类
    Class.forName("com.mysql.jdbc.Driver")
    DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/study", "root", "root");

    在使用了SPI机制之后,就直接可以调用DriverManager.getConnection()方法获取连接了。

  • SLF4J查找日志门面实现
    在未使用SPI机制之前,SLF4J日志门面在查找具体的日志实现时,需要每个实现提供一个叫org.slf4j.com.impl.StaticLoggerBinder.class类,这里其实就跟SPI机制有点类似了,这个类实现了和SPI机制中的配置文件的功能,通过这个类来实现和具体实现的绑定关系。
    20240721170318
    使用了SPI机制之后则是通过SLF4JServiceProvider类来实现和具体实现的绑定关系。
    20240721171037
    20240721174312

    SPI代码实现案例

    假设现在有一个Plugin的接口,调用方通过PluginFactory中的installPlugins方法来加载实现实现类,并进行调用,代码如下所示:

    // Plugin接口
    public interface Plugin {
      boolean install(Map<Object, Object> context);
    }
    
    public class PluginFactory {
      public void installPlugins() {
          Map<Object, Object> context = new HashMap<>();
          context.put("_beans", new ArrayList<>());
          context.put("_version", "1.0.0");
          context.put("_aspects", new HashMap<>());
    
          // 这里通过ServiceLoader加载Plugin的实现类
          ServiceLoader<Plugin> loader = ServiceLoader.load(Plugin.class);
          for (Plugin plugin : loader) {
              plugin.install(context);
          }
      }
    
      public static void main(String[] args) {
          PluginFactory factory = new PluginFactory();
          factory.installPlugins();
      }
    }

    Plugin接口实现者的代码:

    public class LogPlugin implements Plugin {
      private static final Logger LOGGER = LogManager.getLogger();
    
      @Override
      public boolean install(Map<Object, Object> context) {
          LOGGER.info("Login plugin is initiating...");
          return true;
      }
    }

    20240721214035
    20240721214130

使用SPI机制有个好处就是:当需要切换不同的实现类时,无需对业务代码进行适配修改,直接将Maven配置里面的实现依赖切换即可,对于实际的环境可能就是直接将对应的jar包替换到对应的lib目录下,然后重启服务即可。

SPI代码实现原理

ServiceLoader的load方法实现原理是通过接口的全限定名称去读取META-INF/services路径下的文件,获取文件里面实现类的全限定名,然后加载该类,并通过反射的方式调用构造器获取实现类的实例,然后返回,如下图所示:
20240721215047

20240721214737

20240721215650

20240721214937


用户bPbhIAe
16 声望0 粉丝