所以我有一个项目,在其中我使用Spring boot,并希望利用一个模块系统。我希望模块系统能够动态地重新加载。我让它几乎可以工作,但是@ComponentScan在模块中完全不工作。
有一个模块文件夹,包含启动时加载的jar文件,需要动态卸载、加载和重新加载。
模块通过AnnotationConfigApplicationContext创建,上下文的类加载器设置为核心的类加载器,模块接口中的方法提供的@Configuration类通过context.register注册。
@Configuration中的@Bean声明适用于autowire,并且所有类都正确加载。问题是@ComponentScan不起作用。我甚至尝试用@Component注释一个没有字段或任何内容的类,它会抛出一个autowire错误,就像它不在上下文中一样。如果这不是我的存储库中的一个问题,这也不会有什么大不了的。
如果有一种方法可以在没有注释的情况下手动运行componentscan,那么我可以做一些额外的工作。
我已经尝试将spring启动包与@SpringBootApplication一起使用(scanPackages={“package.name”}
@EnableJpaRepository@EntityScan
都在适当的地方,并有正确的参数。
我试着使用。注册到核心上下文中,但它不起作用。无论如何,我不能真正使用它,因为据我所知,您可以取消注册配置。
这是我实际加载jar文件的代码
public Module loadModule(Path path) throws Exception {
if (!path.toFile().exists()) {
throw new Exception(String.format("Could not find module at %s", path.toAbsolutePath()));
}
JarFile file = new JarFile(path.toFile());
ZipEntry moduleJson = file.getEntry("module.json");
System.out.println(path.toUri().toURL());
if (moduleJson == null) {
throw new Exception(String.format("Could not find module json at %s", path.toAbsolutePath()));
}
String moduleJsonSTR = CharStreams
.toString(new InputStreamReader(file.getInputStream(moduleJson), Charsets.UTF_8));
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.setPrettyPrinting().create();
PluginConfig config = gson.fromJson(moduleJsonSTR, PluginConfig.class);
URLClassLoader classLoader = new URLClassLoader(new URL[] { path.toUri().toURL() },
getClass().getClassLoader());
Class mainClass = classLoader.loadClass(config.getMain());
Enumeration<JarEntry> entries = file.entries();
while (entries.hasMoreElements()) {
JarEntry clazz = entries.nextElement();
if (clazz.getName().equals(mainClass.getName())) {
System.out.println("FOUND MAIN AND SKIPPING");
continue;
}
if (clazz.isDirectory() || !clazz.getName().endsWith(".class")) {
continue;
}
String className = clazz.getName().substring(0, clazz.getName().length() - 6);
className = className.replace('/', '.');
classLoader.loadClass(className);
}
Module module = (Module) mainClass.newInstance();
System.out.println(module.getConfigurationClass().getName());
module.setName(config.getName());
file.close();
classLoader.close();
return module;
}
这是我初始化上下文的代码
public AnnotationConfigApplicationContext initializeContext() {
SpringConfig cfg = getSpringConfig();
this.context = new AnnotationConfigApplicationContext();
this.context.setClassLoader(Core.class.getClassLoader());
this.context.refresh();
this.context.register(getConfigurationClass());
Map<String, Object> props = context.getEnvironment().getSystemProperties();
cfg.getProperties().forEach((key, value) -> props.put(key, value));
return context;
}
有一个bean是一个空白类,其中@Component被自动连接到一个类中,在该类中上下文自动连接没有问题。所以我知道autowire正在工作,我知道它是spring管理的,但是@ComponentScan不工作。
我想让ComponentScan工作,或者找到一种以编程方式手动添加组件的方法。
更多代码:
核心插件:这是我的模块类:https://hastebin.com/potayuqali.java 这是加载所述模块的控制器:https://hastebin.com/ipegaqojiv.java 示例模块:
这是其中一个模块的示例:https://hastebin.com/umujiqepob.java 这是该模块的@配置:https://hastebin.com/lakemucifo.css
不幸的是,您的代码链接都不工作,所以很难理解为什么模块的Components
没有注册。
但我知道,如果不让Spring管理bean生命周期,Spring会变得很困难。
对你的应用程序来说,这可能是一个太大的改变,但我不会尝试编写自己的插件系统,而是尝试Java插件框架。这是一个相当典型的插件框架,它还有一个spring插件。
基本上,您可以编写插件,将它们构建为zip/jar,然后将它们放入plugins
文件夹中。
@SpringBootApplication类是否存在于@ComponentScan的一个base Packages的根包中?出于一些奇怪的原因,我仍然在寻找一个解释,将我的SpringBootApplication类从com.comp.app移动到com.comp.app.xyx,从com.comp.app.*加载所有位于其他依赖项中的组件。
如果我理解正确,在加载ApplicationContext之后,您将尝试加载jar并注册为bean。但是ComponentScan在应用程序上下文加载后扫描@Component-like注释。因此,您应该以编程方式注册类(正如您所做的context.register(..)
)。
在注册类之后,您可能有一个@Configuration
注释类,它有一个@Bean
注释方法。要注册@Bean
带注释的方法,可以运行
@Autowire
ConfigurationClassPostProcessor configurationClassPostProcessor;
和
configurationClassPostProcessor.processConfigBeanDefinitions(applicationContext.getDefaultListableBeanFactory());
你也可以看看我的回答:有没有办法扫描所有@组件,比如Spring应用程序上下文加载后的注释类
另一个解决方案:
要扫描基本包(如@ComponentScan),请使用
annotationConfigApplicationContext.scan(basePackageName).
它扫描基本包,并将@ComponentScan作为@ComponentScan注册@Component(etc)带注释的类。但是加载jar的类加载器必须与注释配置应用上下文#类加载器相同。因此,您必须将类Loader设置为:
annotationConfigApplicationContext.setClassLoader(yourClassLoader)
或者AnnotationConfigApplicationContext无法找到并注册类。
请帮帮我!!我到处找了很多,找到了任何有用的信息,或者我有,但我不能在这么短的时间内测试我在web上找到的所有东西,而且spring文档似乎只对普通情况和xml配置非常好,不适合我试图做的疯狂的事情,也不适合编程配置。
问题内容: 我已经阅读了动态bean定义的更改。我在一个简单的代码示例中进行了尝试(请参见下面的代码),并且在不想停止服务器但添加/更改bean定义的情况下,它非常吸引人。 问题: 这样做安全吗(请参见下面的代码)? 我读过,借助or 或?可以在运行时实现bean定义更改。那么区别是什么呢? final static String header = “<?xml version="1.0" enc
我读过动态bean定义更改。我在一个简单的代码示例中尝试了它(参见下面的代码),我发现在不想停止服务器而是添加/更改bean定义的情况下,它非常有吸引力。 问题: null 和都允许我在运行时更改bean定义。但有什么不同,利/弊?
我使用Maven和surefire插件通过扩展AbstractTestNGSpringContextTests来运行TestNG测试,结果显示,即使上下文在类路径中也没有加载,并且测试在我的ide中正常工作,但在Maven中不行。 @contextConfiguration(locations=Array(“classpath*:/com/gottex/gottware/server/offlin
问题内容: 我已经编写了一个PropertyUtils类(来自互联网),它将加载属性 而PropertiesUtil类如下所示 稍后,我可以通过调用PropertiesUtil.getProperty()方法来获取属性。 但是现在我要稍作修改,以便如果myApp.properties被用户修改/更改,则应再次加载 可能我需要FileWatcher类 但我的怀疑是 如何使用classpath:myA
我已经写了一个PropertyUtils类(来自互联网),它将加载属性 PropertiesUtil类如下所示 稍后,我可以通过调用PropertiesUtil来获取属性。getProperty()方法。 但现在我想稍微修改一下,如果myApp。属性被用户修改/更改,应该重新加载 可能我需要FileWatcher类 但我的疑虑是 如何使用classpath创建File对象:myApp/myApp.