昨天我在Tomcat 8上部署我的Java 8 webapp后遇到了一个有趣的问题.我不想如何解决这个问题,而是更了解为什么会发生这种情况.但是,让我们从头开始.
我有两个类定义如下:
Foo.java
package package1;
abstract class Foo {
public String getFoo() {
return "foo";
}
}
Run Code Online (Sandbox Code Playgroud)
Bar.java
package package1;
public class Bar extends Foo {
public String getBar() {
return "bar";
}
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,它们在同一个包中,并最终在同一个jar中,我们称之为commons.jar.这个jar是我的webapp的依赖(即在我的webapp的pom.xml中被定义为依赖).
在我的webapp中,有一段代码可以:
package package2;
public class Something {
...
Bar[] sortedBars = bars.stream()
.sorted(Comparator.comparing(Bar::getBar)
.thenComparing(Bar::getFoo))
.toArray(Bar[]::new);
...
}
Run Code Online (Sandbox Code Playgroud)
当它被执行时,我得到:
java.lang.IllegalAccessError: tried to access class package1.Foo from class package2.Something
Run Code Online (Sandbox Code Playgroud)
玩耍和试验我能够通过三种方式避免错误:
将Foo类更改为public而不是package-private;
将Something类的包更改为"package1"(即字面上与Foo和Bar类相同,但物理上不同的是webapp中定义的Something类);
在执行违规代码之前强制加载Foo:
try {
Class<?> fooClass = Class.forName("package1.Foo");
} …Run Code Online (Sandbox Code Playgroud)我创建了一个简单的测试用例,显示了我目前面临的问题。
我试图做的是手动启动从 CommandLineRunner 嵌入的 Tomcat 并手动部署文件系统上某处可用的 war 文件:
package example;
import java.io.File;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
File tomcatBaseDir = new File("<tomcat-base-dir>");
File warToBeDeployed = new File("<war-to-be-deployed>");
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
tomcat.setBaseDir(tomcatBaseDir.getAbsolutePath());
tomcat.getHost().setAppBase(tomcatBaseDir.getAbsolutePath());
tomcat.getHost().setAutoDeploy(true);
tomcat.getHost().setDeployOnStartup(true);
try {
tomcat.start();
System.out.println("Tomcat started on " + tomcat.getHost());
} catch (LifecycleException e) {
System.err.println("Tomcat could not be started");
System.exit(-1);
}
Context appContext …Run Code Online (Sandbox Code Playgroud) 我目前正在使用 HK2 2.5.0-b05(这是 Jersey 2.24 使用的版本),并且无法执行特定类型的注入。我能够概括我的问题,并提出一个简单的小型测试用例。
代码如下:
package com.github.fabriziocucci.test;
import javax.inject.Inject;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.api.ServiceLocatorFactory;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
public class Test {
private static class A<T> {
private final T t;
@Inject
public A(T t) {
this.t = t;
System.out.println(t);
}
}
private static class B {
}
public static void main(String[] args) {
ServiceLocator serviceLocator = ServiceLocatorFactory.getInstance().create(null);
ServiceLocatorUtilities.bind(serviceLocator, new AbstractBinder() {
@Override
protected void configure() {
bind(B.class).to(B.class);
bindAsContract(new TypeLiteral<A<B>>() {}); // <--- ???
}
});
serviceLocator.getService(new …Run Code Online (Sandbox Code Playgroud)