我正在创建一个URLClassloader来加载一些罐子.每个jar都从不同的类加载器中正确加载,每个jar包含一个带有方法run()的类.现在,这个run()的主体可以在其中创建一个匿名内部类.但是,因为我在try-with-resources块中创建了我的URLClassloader,它会自动关闭,并且在运行时尝试加载匿名内部类时会抛出NoClassDefFoundError,因为类加载器已经关闭.
现在我的问题是,这些情况的正常做法是什么?是否可以让类加载器保持打开状态,以便以后需要加载其他内容时,它可以吗?有没有办法重新打开一个封闭的类加载器?
如果我打开类加载器,编译器会向我发出有关潜在资源泄漏的警告所以我觉得这就像溪流,你不应该让它们无限期地开放.但是由于类加载器的性质,如果它不是加载匿名类的相同类加载器,则它不能在外部类中使用
这是创建类加载器的代码
public Player(File codePath) throws PlayerException {
try (URLClassLoader loader = new URLClassLoader(new URL[] { codePath.toURI().toURL() })) {
//load class from Jar where run() method creates anonymous class that comes in the jar too
} catch (ClassCastException | IOException | ClassNotFoundException | InstantiationException
| IllegalAccessException | IllegalArgumentException | InvocationTargetException
| SecurityException exc) {
throw new PlayerException("Error loading player's code", exc);
}
Run Code Online (Sandbox Code Playgroud) 作为我之前关于类加载的问题的后续跟进
我很好奇注释如何在流行的Spring框架中工作.
据我了解,可能会使用两种机制:
1.字节码上的字节码注入
Spring可以使用自己的类加载器来加载所需的类.在运行时,当加载类并且Spring确定它具有一些适当的注释时,它会注入字节码以向类添加其他属性或行为.
因此,@Controller可以更改注释的控制器以扩展某些控制器基类,并且可以更改函数以在注释时实现路由@RequestMapping.
@Controller
public class HelloWorldController {
@RequestMapping("/helloWorld")
public String helloWorld(Model model) {
model.addAttribute("message", "Hello World!");
return "helloWorld";
}
}
Run Code Online (Sandbox Code Playgroud)
2.用于实例化的反射
@Autowired 可以通过BeanFactory在运行时反射来读取,以处理实例化顺序并实例化已配置的属性.
public class Customer
{
private Person person;
@Autowired
public void setPerson(Person person) {
this.person = person;
}
}
Run Code Online (Sandbox Code Playgroud)
Spring注释如何真正起作用?
我编译我的程序对javaee-api.但是对于Junit测试,我必须使用像glassfish的javaee.jar这样的特定实现来避免像java.lang.ClassFormatError这样的错误:在类文件javax/persistence/Persistence中不是本机或抽象的方法中的Absent Code属性(另请参见1).
因此,请避免使用仅在glassfish实现中可用的方法,我想使用常规api编译我的工件,但是使用实现jar运行junit.但两者都提供相同的命名类和推理,因此类加载器遇到麻烦.
解决这个问题的最佳方法是什么?我可以用maven解决这个问题吗?
非常感谢
如果我在类路径的目录中有一组资源文件,我可以使用它来枚举它们ClassLoader.getResources(location).
例如,如果我/mydir/myresource.properties在类路径上,我可以调用类加载器getResources("mydir")并获取包含的URL的枚举myresource.properties.
当我将完全相同的资源打包到.jar中时,在进行调用时,我在URL的枚举中没有得到任何内容.我只用一个包含那些文件夹的jar替换了文件夹结构(它是一个webapp,所以jar进入/WEB-INF/lib).我还有一些其他的电话getResourceAsStream(location)用于通过名字单独获取其他资源,他们都工作正常.
当资源在.jar中时,枚举资源有什么不同?
更新 - 我复制了(ish)容器外的行为.以下代码段的结果在dirProperties设定为在包装中的资源名称具有对象键,但如果包是在一个.jar抛出Properties.load(InputStream的)方法中一个NullPointerException.
Properties dirProperties = new Properties();
dirProperties.load(this.getClass().getClassLoader().getResourceAsStream(location));
Run Code Online (Sandbox Code Playgroud)
容器上的相同代码(Tomcat 5.5)不会抛出异常,但是当文件位于.jar中时会生成一个空的Properties对象.
我写了自己的类加载器.我需要使用类加载器加载所有类.我已通过VM以下内容:-Djava.system.class.loader=MyClassLoader
只使用我的类加载器加载我的包中第一个引用的类.我的包中的其他类正在使用AppClassLoader.
这是MyClassLoader看起来像:
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
public class MyClassLoader extends ClassLoader {
public MyClassLoader() {
super(MyClassLoader.class.getClassLoader());
}
public MyClassLoader(ClassLoader parent) {
super(parent);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
System.out.println("MyClassLoader is loading " + name);
return super.loadClass(name);
}//loadClass
@Override
public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
System.out.println("MyClassLoader is loading " + name + " with resolve = " + resolve);
return super.loadClass(name, resolve);
}
@Override …Run Code Online (Sandbox Code Playgroud) 我希望JBoss只使用我的war文件中的依赖项.每次我部署这个war文件时,JBoss仍然使用自己的jar.
这是jboss-web.xml我用的:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<class-loading java2ClassLoadingCompliance="false">
<loader-repository>
my.package:loader=my-app.war
<loader-repository-config>
java2ParentDelegation=false
</loader-repository-config>
</loader-repository>
</class-loading>
</jboss-web>
Run Code Online (Sandbox Code Playgroud)
和jboss-classloading.xml:
<?xml version="1.0" encoding="UTF-8"?>
<classloading
xmlns="urn:jboss:classloading:1.0"
export-all="NON_EMPTY"
import-all="true"
parent-first="false"/>
Run Code Online (Sandbox Code Playgroud)
JBoss 5.1.0.GA
我很难写这个问题的标题,但这是我的情况,我要问的是:
我想我的问题的根源是:在加载并运行应用程序后是否需要.class文件? 类只是存储在内存中,我不再需要文件系统上的文件了吗?或者它仍然访问/读取文件系统上的东西?
任何洞察或更好地理解java正在运行的应用程序需要什么是值得赞赏的.
我有这个代码:
public abstract class Person {
public static final class Guy extends Person {
public static final Guy TOM = new Guy();
public static final Guy DICK = new Guy();
public static final Guy HARRY = new Guy();
}
public static final List<Guy> GUYS = ImmutableList.of(Guy.TOM, Guy.DICK, Guy.HARRY);
}
Run Code Online (Sandbox Code Playgroud)
我知道,看起来它应该是一个枚举,它会是,但它需要继承自Person,一个抽象类.
我的问题是:如果我试图访问Guys列表,我没关系.但是我尝试特别访问任何一个Guy,我有一个问题:Guy之前加载Person.但是,由于Guy继承Person,Person加载和尝试访问TOM,但由于Guy已经加载,因此无法再次开始加载,因此我们有一个空引用.(并且ImmutableList不接受null,所以我们得到一个例外.)
所以我知道为什么会这样,但我不知道如何避免它.我可以将List移动到Guy类中,但是我将有多个实现Person,并且我想拥有类中所有Persons 的主列表Person.
我觉得很有可能加载静态内部类而不加载它的包含类,但我想这是有道理的.有什么方法可以解决这个问题吗?
我对java还是比较陌生,所以如果这个问题看起来很“傻”,请原谅我。我知道JVM (Java虚拟机)包含在JRE (Java运行时环境)中但是我不确定类加载器和执行引擎是否是JVM的一部分。
我读过的大多数资料都没有说明这一点。相反,在描述JVM的组件时,它们仅讨论运行时数据区 的5个组件(即,堆,JVM堆栈,方法区域,PC寄存器和本机方法堆栈)。虽然我的常识告诉我们要使其成为完整的虚拟机,但它需要输入,内存和处理,但我仍然需要验证这些组件的确切位置。
下面的代码将jar文件添加到构建路径,它适用于Java 8.但是,它会抛出Java 9的异常,该异常与转换为URLClassLoader有关.有什么想法可以解决这个问题吗?最佳解决方案将对其进行编辑以与Java 8和9一起使用.
private static int AddtoBuildPath(File f) {
try {
URI u = f.toURI();
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class<URLClassLoader> urlClass = URLClassLoader.class;
Method method = urlClass.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(urlClassLoader, u.toURL());
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException | MalformedURLException | IllegalAccessException ex) {
return 1;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud) classloader ×10
java ×8
annotations ×1
classpath ×1
git ×1
jar ×1
java-9 ×1
jboss5.x ×1
jvm ×1
maven-2 ×1
resources ×1
spring ×1
spring-ioc ×1
static ×1
unit-testing ×1
war ×1