Java的SPI机制及AutoService

一、SPI机制

SPI:Service Provider Interface,是一种服务发现机制

它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类,模块之间基于接口编程,实现可拔插

二、栗子

1.定义接口

package com.zz.spi;

public interface SPIService {
    void execute();
}

2.实现类

SPIImpl1.java

package com.zz.spi;

public class SPIImpl1 implements SPIService {
    @Override
    public void execute() {
        System.out.println("SPIImpl1 execute()");
    }
}

SPIImpl2.java

package com.zz.spi;

public class SPIImpl2 implements SPIService {
    @Override
    public void execute() {
        System.out.println("SPIImpl2 execute()");
    }
}

3.定义文件

ClassPath下,META-INF/services目录下创建一个以"接口全限定名"为命名的文件:

内容为实现类的全限定名:

com.zz.spi.SPIImpl1
com.zz.spi.SPIImpl2

4.使用

有两个类可以得到实现类的实例,sun.misc.Servicejava.util.ServiceLoader

package com.zz.spi;

import sun.misc.Service;

import java.util.Iterator;
import java.util.ServiceLoader;

public class Main {
    public static void main(String[] args) {
        Iterator<SPIService> providers = Service.providers(SPIService.class);
        ServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class);

        while (providers.hasNext()) {
            SPIService service = providers.next();
            service.execute();
        }
        System.out.println("- - - - - - - - - - - - - -");
        Iterator<SPIService> iterator = load.iterator();
        while (iterator.hasNext()) {
            SPIService service = iterator.next();
            service.execute();
        }
    }
}

结果:

三、JDBC中的应用

1.未用SPI机制

如果未用SPI机制,需要使用Class.forName()加载驱动

@Test
public void test1() throws SQLException, ClassNotFoundException {
    Class.forName("com.mysql.cj.jdbc.Driver");
    String url = "jdbc:mysql://localhost:3306";
    String user = "root";
    String password = "123456";
    Connection conn = DriverManager.getConnection(url, user, password);
    System.out.println(conn);
}

为什么需要加载驱动,查看源码,可以看出,当加载驱动时,会执行驱动类的static代码块,此代码块的作用是向DriverManager注册驱动,这样DriverManager.getConnection()便可以获得连接

2.使用SPI机制

对于高版本的jdk和mysql驱动,不再需要使用Class.forName()加载驱动

@Test
public void test2() throws SQLException {
    String url = "jdbc:mysql://localhost:3306";
    String user = "root";
    String password = "123456";
    Connection conn = DriverManager.getConnection(url, user, password);
    System.out.println(conn);
}

分析:

对于com.mysql.cj.jdbc.Driver,其jar文件META-INF/services目录下创建了java.sql.Driver,内容是Driver实现类的全限定名

 

对于DriverManager类

driversIterator.next()会创建Driver实例,所以此时会执行com.mysql.cj.jdbc.Driver的代码,注册到DriverManager

四、其他

1.AutoService

可以使用google的AutoService组件会自动在编译后的ClassPath下生成文件META-INF/services/com.zz.spi.SPIService文件

添加maven依赖

<dependency>
    <groupId>com.google.auto.service</groupId>
    <artifactId>auto-service</artifactId>
    <version>1.0-rc2</version>
</dependency>

在实现类上加上类注解@AutoService

SPIImpl1.java

package com.zz.spi;

import com.google.auto.service.AutoService;

@AutoService(SPIService.class)
public class SPIImpl1 implements SPIService {

    @Override
    public void execute() {
        System.out.println("SPIImpl1 execute()");
    }
}

SPIImpl2.java

package com.zz.spi;

import com.google.auto.service.AutoService;

@AutoService(SPIService.class)
public class SPIImpl2 implements SPIService {

    @Override
    public void execute() {
        System.out.println("SPIImpl2 execute()");
    }
}

 

Java中的autoservice注解是一种用于服务发现的机制,它能够自动将服务的实现类注册到指定的配置文件中,一般是META-INF/services目录下的文件。 然而,的确有一些情况下autoservice注解无法生成META-INF文件。这可能是由于以下几种原因导致的: 1. 编译问题:可能是由于编译配置的问题,导致编译器无法正确处理autoservice注解。这种情况下,我们可以尝试检查编译器的配置,或者使用其他IDE或编译工具进行尝试。 2. 库或框架限制:有些库或框架可能不支持autoservice注解,或者在使用autoservice注解时会有特殊的要求。我们可以查看相关库或框架的文档,了解其对autoservice注解的支持情况,或者尝试其他方式实现服务发现。 3. 配置文件缺失或错误:autoservice注解生成META-INF文件的前提是META-INF目录存在,并且配置文件的名称和路径正确。如果自动生成的META-INF文件不存在,或者文件名或路径有误,就无法实现服务发现。我们需要检查项目的文件结构,确认META-INF目录是否存在,并且配置文件的名称和路径是否正确。 总之,虽然autoservice注解通常可以自动将服务实现类注册到META-INF文件中,但在某些情况下可能会遇到无法生成META-INF文件的问题。我们需要仔细检查编译配置、库或框架限制,以及配置文件是否正确等因素,以找出问题所在,并采取相应的解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值