gpt4 book ai didi

Freemarker removeIntrospectionInfo 在模型热交换后不适用于 DCEVM

转载 作者:行者123 更新时间:2023-12-04 20:39:39 26 4
gpt4 key购买 nike

我正在使用 Freemarker 和 DCEVM+HotSwapManager 代理。这基本上允许我即使在添加/删除方法时也可以热交换类。

在 Freemarker 使用热交换类作为模型之前,一切都像魅力一样工作。它抛出 freemarker.ext.beans.InvalidPropertyException: No such bean property on me 即使反射表明该方法存在(在调试 session 期间检查)。

我在用

final Method clearInfoMethod = beanWrapper.getClass().getDeclaredMethod("removeIntrospectionInfo", Class.class);
clearInfoMethod.setAccessible(true);
clearInfoMethod.invoke(clazz);

清除缓存,但它不起作用。我什至尝试获取 classCache 成员字段并使用反射清除它,但它也不起作用。

我究竟做错了什么?
我只需要强制 freemarker 放弃对他已经获得的模型类/类的任何自省(introspection)。

有什么办法吗?

更新

示例代码

应用程序.java
// Application.java
public class Application
{
public static final String TEMPLATE_PATH = "TemplatePath";
public static final String DEFAULT_TEMPLATE_PATH = "./";

private static Application INSTANCE;
private Configuration freemarkerConfiguration;
private BeansWrapper beanWrapper;

public static void main(String[] args)
{
final Application application = new Application();
INSTANCE = application;
try
{
application.run(args);
}
catch (InterruptedException e)
{
System.out.println("Exiting");
}
catch (IOException e)
{
System.out.println("IO Error");
e.printStackTrace();
}
}

public Configuration getFreemarkerConfiguration()
{
return freemarkerConfiguration;
}

public static Application getInstance()
{
return INSTANCE;
}

private void run(String[] args) throws InterruptedException, IOException
{
final String templatePath = System.getProperty(TEMPLATE_PATH) != null
? System.getProperty(TEMPLATE_PATH)
: DEFAULT_TEMPLATE_PATH;

final Configuration configuration = new Configuration();
freemarkerConfiguration = configuration;

beanWrapper = new BeansWrapper();
beanWrapper.setUseCache(false);
configuration.setObjectWrapper(beanWrapper);
try
{
final File templateDir = new File(templatePath);
configuration.setTemplateLoader(new FileTemplateLoader(templateDir));
}
catch (IOException e)
{
throw new RuntimeException(e);
}

final RunnerImpl runner = new RunnerImpl();
try
{
runner.run(args);
}
catch (RuntimeException e)
{
e.printStackTrace();
}
}

public BeansWrapper getBeanWrapper()
{
return beanWrapper;
}
}

RunnerImpl.java
// RunnerImpl.java
public class RunnerImpl implements Runner
{
@Override
public void run(String[] args) throws InterruptedException
{
long counter = 0;
while(true)
{
++counter;
System.out.printf("Run %d\n", counter);
// Application.getInstance().getFreemarkerConfiguration().setObjectWrapper(new BeansWrapper());
Application.getInstance().getBeanWrapper().clearClassIntrospecitonCache();
final Worker worker = new Worker();
worker.doWork();
Thread.sleep(1000);
}
}

Worker.java
// Worker.java
public class Worker
{
void doWork()
{
final Application application = Application.getInstance();
final Configuration freemarkerConfiguration = application.getFreemarkerConfiguration();

try
{
final Template template = freemarkerConfiguration.getTemplate("test.ftl");
final Model model = new Model();
final PrintWriter printWriter = new PrintWriter(System.out);

printObjectInto(model);
System.out.println("-----TEMPLATE MACRO PROCESSING-----");
template.process(model, printWriter);
System.out.println();
System.out.println("-----END OF PROCESSING------");
System.out.println();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (TemplateException e)
{
e.printStackTrace();
}
}

private void printObjectInto(Object o)
{
final Class<?> aClass = o.getClass();
final Method[] methods = aClass.getDeclaredMethods();
for (final Method method : methods)
{
System.out.println(String.format("Method name: %s, public: %s", method.getName(), Modifier.isPublic(method.getModifiers())));
}
}
}

模型.java
// Model.java    
public class Model
{
public String getMessage()
{
return "Hello";
}

public String getAnotherMessage()
{
return "Hello World!";
}
}

这个例子根本不起作用。即使在运行时更改 BeansWrapper 也不会产生任何影响。

最佳答案

BeansWrapper (和 DefaultObjectWrapper 等)内省(introspection)缓存依赖于 java.beans.Introspector.getBeanInfo(aClass) ,而不是反射(reflection)。 (这是因为它将对象视为 JavaBeans。)java.beans.Introspector有自己的内部缓存,所以它可以返回陈旧的信息,在这种情况下 BeansWrapper只会根据过时的信息重新创建自己的类内省(introspection)数据。截至java.beans.Introspector的缓存,它实际上是正确的,因为它建立在 Java 中的类是不可变的假设之上。如果有什么东西违反了这个基本规则,它应该确保 java.beans.Introspector的缓存被清除(以及许多其他缓存......),否则不仅仅是 FreeMarker 会破坏。例如,在 JRebel,他们付出了很多努力来清除所有类型的缓存。我猜 DCEVM 没有这方面的资源。那么,看来您必须调用 Introspector.flushCaches()你自己。

更新:一段时间(Java 7,也许是 6)java.beans.Introspector每个线程组有一个缓存,因此您可以调用 flushCaches()来自所有线程组。而这一切实际上都是实现细节,原则上可以随时更改。可悲的是,Introspector.flushCaches() 的 JavaDoc不警告你...

关于Freemarker removeIntrospectionInfo 在模型热交换后不适用于 DCEVM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28721199/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com