자바 플러그 인 확장 메커니즘 SPI 사례 설명
SPI 는 모두 Service Provider Interface 라 고 부 르 며 서비스 발견 메커니즘 이다.그것 은 프레임 워 크 에 대외 적 으로 확장 가능 한 능력 을 제공 했다.
인터페이스 클래스-구현 클래스 가 제공 하 는 RPC 방식 과 어떤 차이 가 있 습 니까?
public interface AdOpFromApolloService {}
public class AdOpFromDbServiceImpl implements AdOpFromDbService {}
만약 우리 가 RPC 를 실현 해 야 한다 고 가정 하면 어떻게 하 는 것 입 니까?RPC 는 대응 하 는 인터페이스 클래스 인 AdOpFromApolloService 에 RPC 클래스 를 표시 하 는 데 사용 할 주 해 를 추가 한 다음,현재 클래스 를 의존 패키지 에 두 고 다른 항목 에 제공 하여 인터페이스 클래스 를 통 해 호출 합 니 다.
요컨대 RPC 호출 에서 인터페이스 클래스 만 제공 한 다음 에 제3자 호출(제3자 만 조정 하고 작성 하지 않 음)
그럼 RPC 는 도대체 SPI 와 어떤 관계 인가요?
프레임 워 크 구현 사례:
다음은 두 항목 모듈 로 SPI 의 용법 을 설명 하고,먼저 항목 구조 도 를 보면 다음 과 같다.
다음은 이 루어 지 는 과정 입 니 다.
첫 번 째 단계:spi-demo-contract 프로젝트 를 만 들 고 resources 디 렉 터 리 에 다음 디 렉 터 리(MATE-INFF/services)와 파일(com.example.spidemocact.spi.spi.SpiTestDemoService)을 새로 만 듭 니 다.
두 번 째 단계:spi-demo 프로젝트 를 만 들 고 spi-demo-contract 의존 도 를 도입 합 니 다.
추가 설명:우 리 는 성명 류 의 우선 순 위 를 다시 써 서 어떤 실현 류 로 처리 해 야 하 는 지 판단 할 수 있다.예 를 들 어 우선 순위=0 최고 우선 순 위 를 다시 쓰 고 불 러 올 때 기본 값 은 첫 번 째 우선 순위 가 가장 높 은 것 만 가 져 옵 니 다.그러면 우리 가 다시 쓴 사용자 정의 구현 클래스 는 기본 SPI 구현 클래스 를 덮어 쓸 수 있 습 니 다.
상세 한 절 차 는 아래 와 같다.
-- resources
---- META-INF
-------- services
------------ com.example.spidemocontract.spi.SpiTestDemoService
com.example.spidemocontract.spi.impl.DefaultSpiTestDemoService
/**
* resources/META-INF/services/com.example.spidemocontract.spi.impl.DefaultSpiTestDemoService
**/
public interface SpiTestDemoService {
void printLog();
int getOrder();
}
/**
* , SPI
*/
public class DefaultSpiTestDemoService implements SpiTestDemoService {
@Override
public int getOrder() {
return Integer.MAX_VALUE;
}
@Override
public void printLog() {
System.out.println(" DefaultSpiTestDemoService log");
}
}
<dependency>
<groupId>com.example</groupId>
<artifactId>spi-demo-contract</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
-- resources
---- META-INF
-------- services
------------ com.example.spidemocontract.spi.SpiTestDemoService
com.example.spidemo.spi.OtherSpiTestDemoService
/**
* ,
*/
public class OtherSpiTestDemoService implements SpiTestDemoService {
// SPI , order ,
@Override
public int getOrder() {
return 0;
}
@Override
public void printLog() {
System.out.println(" OtherSpiTestDemoService log");
}
}
public static void main(String[] args) {
// SPI
Iterator<SpiTestDemoService> iterator = ServiceLoader.load(SpiTestDemoService.class).iterator();
// ordered, ordered , ,
List<SpiTestDemoService> list = Lists.newArrayList(iterator)
.stream().sorted(Comparator.comparing(SpiTestDemoService::getOrder))
.collect(Collectors.toList());
for (SpiTestDemoService item : list) {
item.printLog();
}
}
중간 부품 은 어떻게 SPI 를 실현 합 니까?Apollo-Client 의 실현
// resource/META-INF/services com.ctrip.framework.apollo.spring.spi.ConfigPropertySourcesProcessorHelper
public interface ConfigPropertySourcesProcessorHelper extends Ordered {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
public class DefaultConfigPropertySourcesProcessorHelper implements ConfigPropertySourcesProcessorHelper {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// ..... bean,
}
@Override
public int getOrder() {
// 。 spi
return Ordered.LOWEST_PRECEDENCE;
}
}
사용자 정의 SPI 구현 우선 순 위 를 높 게 설정 할 수 있 기 때문에 기본 구현 을 덮어 쓰 는 목적 을 달성 할 수 있 습 니 다.
public static <S extends Ordered> S loadPrimary(Class<S> clazz) {
List<S> candidates = loadAllOrdered(clazz);
return candidates.get(0);
}
public static <S extends Ordered> List<S> loadAllOrdered(Class<S> clazz) {
Iterator<S> iterator = loadAll(clazz);
if (!iterator.hasNext()) {
throw new IllegalStateException(String.format(
"No implementation defined in /META-INF/services/%s, please check whether the file exists and has the right implementation class!",
clazz.getName()));
}
// SPI , ,
List<S> candidates = Lists.newArrayList(iterator);
Collections.sort(candidates, new Comparator<S>() {
@Override
public int compare(S o1, S o2) {
// the smaller order has higher priority
return Integer.compare(o1.getOrder(), o2.getOrder());
}
});
return candidates;
}
JDBC 의 실현
com.example.app.driver.MyDriver
public class MyDriver extends NonRegisteringDriver implements Driver {
static {
try {
java.sql.DriverManager.registerDriver(new MyDriver());
} catch (SQLException e) {
throw new RuntimeException("Can't register driver!", e);
}
}
public MyDriver() throws SQLException {}
@Override
public Connection connect(String url, Properties info) throws SQLException {
System.out.println("MyDriver - .url:" + url);
System.out.println("JDBC :" + info);
info.setProperty("user", "root");
Connection connection = super.connect(url, info);
System.out.println("MyDriver - !" + connection.toString());
return connection;
}
}
String url = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
String user = "root";
String password = "root";
Class.forName("com.example.app.driver.MyDriver");
Connection connection = DriverManager.getConnection(url, user, password);
// ( , , )
for(DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
자바 플러그 인 확장 메커니즘 의 SPI 사례 에 대한 설명 은 여기까지 입 니 다.더 많은 자바 플러그 인 확장 메커니즘 의 SPI 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 지원 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.