SPI(Service Provider Interface)는 JDK에 내장된 서비스 검색 메커니즘으로, 프레임워크 확장 및 대체 구성 요소를 활성화하는 데 사용할 수 있습니다. 주로 Dubbo, Spring, Common-Logging, JDBC 등은 SPI 메커니즘을 채택하고 동일한 인터페이스에 대해 서로 다른 구현을 사용하여 이를 다른 사용자에게 제공함으로써 프레임워크의 확장성을 향상시킵니다.
Java에 내장된 SPI는 java.util.ServiceLoader 클래스를 통해 classPath 및 jar 패키지의 META-INF/services/ 디렉터리에 있는 인터페이스의 정규화된 이름으로 명명된 파일을 구문 분석하고 로드합니다. 파일에 지정된 인터페이스 클래스를 구현하여 호출을 완료합니다.
public interface VedioSPI { void call(); }
public class Mp3Vedio implements VedioSPI { @Override public void call() { System.out.println("this is mp3 call"); } }
public class Mp4Vedio implements VedioSPI { @Override public void call() { System.out.println("this is mp4 call"); } }
프로젝트 소스 디렉토리에 새로운 META-INF/services/ 디렉토리를 생성하고 com.skywares.fw를 생성합니다. juc.spi .VedioSPI 파일.
public class VedioSPITest { public static void main(String[] args) { ServiceLoader<VedioSPI> serviceLoader =ServiceLoader.load(VedioSPI.class); serviceLoader.forEach(t->{ t.call(); }); } }
설명: Java는 서비스에서 제공하는 도구 클래스를 찾기 위해 ServiceLoader를 통해 spi를 구현합니다.
위는 Java에 내장된 SPI 기능을 구현하는 간단한 예입니다. 구현 원리는 ServiceLoader가 서비스 제공 인터페이스를 찾기 위해 내장된 Java 도구 클래스라는 것입니다. load() 메소드를 호출하여 서비스 제공 인터페이스를 검색하고, 마지막으로 서비스 제공 인터페이스의 구현 클래스에 하나씩 액세스하기 위해 순회합니다. .
소스 코드에서 찾을 수 있습니다.
ServiceLoader 클래스 자체는 Iterable 인터페이스를 구현하고 그 안에 반복자 메서드를 구현합니다. 구문 분석 후 내부 클래스 LazyIterator의 메서드를 호출합니다. 서비스 제공자 인터페이스 파일 최종 결과는 Iterator에 반환되며, 서비스에서 제공하는 인터페이스 구현 클래스에 대한 직접 접근은 지원되지 않습니다.
모든 서비스 제공자 인터페이스에 해당하는 파일은 META-INF/services/ 디렉토리에 위치합니다. 최종 유형은 PREFIX 디렉토리를 변경할 수 없도록 결정합니다.
Java에서 제공하는 SPI 메커니즘의 아이디어는 매우 훌륭하지만 이에 상응하는 단점도 있습니다. 자세한 내용은 다음과 같습니다.
Java의 내장 메소드는 순회를 통해서만 얻을 수 있습니다.
서비스 공급자 인터페이스는 META-INF/services/ 디렉터리에 있어야 합니다.
Java의 spi에 존재하는 문제를 고려하여 Spring의 SPI 메커니즘은 SPI의 아이디어를 따르지만 이를 확장하고 최적화합니다.
Spring SPI는 Java SPI의 설계 아이디어를 따릅니다. Spring은 spring.factories 메서드를 사용하여 Spring 소스 코드를 수정하지 않고도 Spring 프레임워크의 확장성을 제공할 수 있는 SPI 메커니즘을 구현합니다.
Spring 예시
인터페이스 정의
public interface DataBaseSPI { void getConnection(); }
관련 구현
#DB2实现 public class DB2DataBase implements DataBaseSPI { @Override public void getConnection() { System.out.println("this database is db2"); } } #Mysql实现 public class MysqlDataBase implements DataBaseSPI { @Override public void getConnection() { System.out.println("this is mysql database"); } }
1. 프로젝트의 META-INF 디렉토리에 spring.factories 파일
2을 추가합니다.
com.skywares.fw.juc.springspi.DataBaseSPI = com.skywares.fw.juc.springspi.DB2DataBase, com.skywares.fw.juc.springspi.MysqlDataBase
Description 여러 구현은 다음과 같이 구분됩니다. 쉼표.
관련 테스트 클래스
public class SpringSPITest { public static void main(String[] args) { List<DataBaseSPI> dataBaseSPIs =SpringFactoriesLoader.loadFactories(DataBaseSPI.class, Thread.currentThread().getContextClassLoader()); for(DataBaseSPI datBaseSPI:dataBaseSPIs){ datBaseSPI.getConnection(); } } }
출력 결과
예제를 보면 Spring이 SPI를 구현하기 위해 spring.factories를 사용하고 SPI를 구현하기 위해 java를 사용하는 것을 볼 수 있습니다. 그러나 spring의 spi 메소드는 특히 java의 spi에 최적화되어 있습니다. 내용은 다음과 같습니다.
Java SPI는 구성 파일에 해당하는 서비스 제공 인터페이스입니다. 구성 파일에는 현재 인터페이스의 모든 구현 클래스가 저장되어 있습니다.
Spring 팩토리 SPI는 다중 인터페이스와 해당 구현 클래스를 저장하는 spring.factories 구성 파일입니다. 인터페이스의 정규화된 이름이 키로 사용되며 구현 클래스가 다중 구현으로 구성됩니다. 클래스는 쉼표로 구분되며 스프링만 구성 파일을 생성합니다.
그러면 spring.factories를 로드하여 SpI를 어떻게 구현합니까? 소스 코드를 통해 추가로 분석할 수 있습니다.
설명: loadFactoryNames는 spring.factories 파일에서 지정된 인터페이스의 구현 클래스의 정규화된 이름을 구문 분석합니다. 구체적인 구현은 다음과 같습니다.
설명: 모든 jar 패키지에서 META-INF/spring.factories의 파일 경로를 가져와서 열거형 값으로 반환합니다. spring.factories 파일 경로를 탐색하여 하나씩 로드하고 구문 분석하고, FactoryClass 유형의 구현 클래스 이름을 통합하고, 구현 클래스의 전체 클래스 이름을 얻은 후, 해당 클래스의 인스턴스 작업을 수행합니다.
설명: 인스턴스화는 리플렉션을 통해 해당 초기화가 이루어집니다.
위 내용은 SpringBoot의 SPI 메커니즘을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!