gpt4 book ai didi

java - 子一级加载器和服务提供者接口(interface) (SPI)

转载 作者:行者123 更新时间:2023-12-01 17:31:57 27 4
gpt4 key购买 nike

我找到了custom class loader ,它按照子优先原则加载类。它工作正常,但我遇到了以下问题。当我尝试加载使用 SPI 的类时,出现异常:

Exception in thread "main" java.util.ServiceConfigurationError: test.spi.SayMyNameProvider: test.spi.ImplProvider not a subtype

我创建了simple SPI project包含模块:spi-api、spi-impl 和 spi-app。

当我使用 URLClassLoader 时它可以工作,但是每当我使用 ChildFirstClassLoader 时我都会收到上面提到的异常:

public class TestMain {
public static void main(String[] args) throws MalformedURLException {

//!!! comment ChildFirstClassLoader and uncomment URLClassLoader to get the correct behavior
ChildFirstClassLoader classLoader = getCustomClassLoader();
//URLClassLoader classLoader = getUrlClassLoader();

ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);

try {
List<SayMyNameProvider> providers = Speaker.providers();
for (SayMyNameProvider provider : providers) {
SayMyNameManager sayMyNameManager = provider.create();
sayMyNameManager.sayIt("main");
}
System.out.println("done");

} finally {
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}

private static ChildFirstClassLoader getCustomClassLoader() throws MalformedURLException {
URL[] urls = getUrls();

return new ChildFirstClassLoader(urls);
}

private static URLClassLoader getUrlClassLoader() throws MalformedURLException {
URL[] urls = getUrls();

return new URLClassLoader(urls);
}

private static URL[] getUrls() throws MalformedURLException {
File spiImpl = Paths.get("spi-impl", "target", "spi-impl-1.0.0-SNAPSHOT.jar").toFile();
File spiApi = Paths.get("spi-api", "target", "spi-api-1.0.0-SNAPSHOT.jar").toFile();

URL[] urls = new URL[2];
urls[0] = spiImpl.toURI().toURL();
urls[1] = spiApi.toURI().toURL();
return urls;
}
}

也许有人以前已经遇到过这个问题并且知道如何解决它。如果您有任何帮助或建议,我将不胜感激。

最佳答案

所以,三天后我终于得到了我的问题的答案。它说我很愚蠢:)因为在 article最后,作者提供了具有正确行为的示例,并且它适用于我的情况。但是,它在我的其他带有 slf4j 和 logback 依赖项的测试中不起作用。但令我惊讶的是,没有系统类加载器的代码可以工作。简而言之,我尝试使用不同版本的 slf4j 和 logback。

Pom.xml:

<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>

TestMain.class

public class TestMain {
private static Logger log = LoggerFactory.getLogger(TestMain.class);

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, MalformedURLException {
log.info("Hello");

ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

ChildFirstClassLoader2 classLoader = new ChildFirstClassLoader2(getUrls());

Thread.currentThread().setContextClassLoader(classLoader);

try {
Class<?> testClass = classLoader.loadClass("petrovskyi.TestClass");
Object o = testClass.getDeclaredConstructor().newInstance();
Method test = testClass.getMethod("test");
test.setAccessible(true);
test.invoke(o);

} finally {
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}

private static URL[] getUrls() throws MalformedURLException {
File libDir = Paths.get("src","main", "resources", "testClasses").toFile();

URL[] urls;

List<URL> urlsList = new ArrayList<>();

URL classUrl = libDir.toURI().toURL();
urlsList.add(classUrl);

try (Stream<Path> walk = Files.walk(libDir.toPath())) {
List<File> result = walk.map(Path::toFile)
.filter(x -> x.getName().endsWith(".jar"))
.collect(Collectors.toList());

for (File jarFile : result) {
urlsList.add(jarFile.toURI().toURL());
}
} catch (IOException e) {
throw new RuntimeException("Error while walking through " + libDir + " to find jar files", e);
}

urls = urlsList.toArray(new URL[0]);
return urls;
}
}

上面我尝试从某个目录获取所有 jar 。 jar 是下一个:

  • logback-classic-1.3.0-alpha5.jar
  • logback-core-1.3.0-alpha5.jar
  • slf4j-api-2.0.0-alpha1.jar

TestClass.class

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import org.slf4j.spi.DefaultLoggingEventBuilder;
import org.slf4j.spi.LoggingEventBuilder;

public class TestClass {
private static Logger log = LoggerFactory.getLogger(TestClass.class);

public TestClass() {
}

public void test() {
LoggingEventBuilder loggingEventBuilder = new DefaultLoggingEventBuilder(log, Level.ERROR);
loggingEventBuilder.log(" =========== Hello, World! ===========");
log.info("Test from test class");
}
}

上面的类使用了 pom.xml 中提到的 slf4j 版本中不存在的 LoggingEventBuilder

ChildFirstClassLoader2.class

public class ChildFirstClassLoader2 extends URLClassLoader {

public ChildFirstClassLoader2(URL[] urls) {
super(URLs);
}

@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> loadedClass = findLoadedClass(name);
if (loadedClass == null) {

try {
if (loadedClass == null) {
loadedClass = findClass(name);
}

} catch (ClassNotFoundException e) {
loadedClass = super.loadClass(name, resolve);
}
}

if (resolve) {
resolveClass(loadedClass);
}
return loadedClass;
}


@Override
public Enumeration<URL> getResources(String name) throws IOException {
List<URL> allRes = new LinkedList<>();

Enumeration<URL> thisRes = findResources(name);
if (thisRes != null) {
while (thisRes.hasMoreElements()) {
allRes.add(thisRes.nextElement());
}
}

Enumeration<URL> parentRes = super.findResources(name);
if (parentRes != null) {
while (parentRes.hasMoreElements()) {
allRes.add(parentRes.nextElement());
}
}

return new Enumeration<URL>() {
Iterator<URL> it = allRes.iterator();

@Override
public boolean hasMoreElements() {
return it.hasNext();
}

@Override
public URL nextElement() {
return it.next();
}
};
}

@Override
public URL getResource(String name) {
URL res = null;

if (res == null) {
res = findResource(name);
}
if (res == null) {
res = super.getResource(name);
}
return res;
}
}

输出:

2020-04-10 12:01:39,928 [main] INFO TestMain - Hello
2020-04-10 12:01:40,095 [main] ERROR TestClass - =========== Hello, World! ===========
2020-04-10 12:01:40,097 [main] INFO TestClass - Test from test class

关于java - 子一级加载器和服务提供者接口(interface) (SPI),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61103197/

27 4 0
文章推荐: java - 无序 XSD 序列的标准解决方案
文章推荐: java - 尝试在 Thymeleaf Spring Boot 中迭代 List() 时出现 "Exception evaluating SpringEL expression"错误