我在“aspectj”模式下使用 Spring 的声明式事务(@Transactional 注释)。它在大多数情况下都能正常工作,但在某些情况下却不能。我们可以称它为 Lang(因为这就是它的实际名称)。
我已经能够将问题精确定位到加载时间编织器。通过在 aop.xml 中打开调试和详细日志记录,它会列出所有正在编织的类。日志中确实根本没有提到有问题的类 Lang。
然后我在Lang的顶部打了一个断点,导致Eclipse在加载Lang类时挂起线程。这个断点是在 LTW 编织其他类时命中的!所以我猜它要么尝试编织 Lang 并失败并且不输出它,要么其他一些类有一个引用强制它在实际获取之前加载 Lang有机会编织它。
但是我不确定如何继续调试它,因为我无法以较小的规模重现它。关于如何继续的任何建议?
更新:也欢迎提供其他线索。例如,LTW 实际上是如何运作的?似乎发生了很多魔法。是否有任何选项可以从 LTW 获得更多调试输出?我目前有:
<weaver options="-XnoInline -Xreweavable -verbose -debug -showWeaveInfo">
我忘了之前提到它:spring-agent 被用来允许 LTW,即 InstrumentationLoadTimeWeaver。
根据 Andy Clement 的建议,我决定检查 AspectJ 转换器是否曾经通过类(class)。我在 ClassPreProcessorAgent.transform(..) 中放置了一个断点,看起来 Lang 类甚至从未到达该方法,尽管它是由与其他类(Jetty 的 WebAppClassLoader 的实例)。
然后我继续在 InstrumentationLoadTimeWeaver$FilteringClassFileTransformer.transform(..) 中放置一个断点。 Lang 甚至连那个都没有命中。而且我认为应该为所有 加载的类调用该方法,而不管它们使用的是什么类加载器。这开始看起来像:
Lang 在 Eclipse 报告加载时未加载下一条线索:我打开了 -verbose:class 并且看起来好像 Lang is 被过早地加载了——可能在转换器加载之前添加到仪器。奇怪的是,我的 Eclipse 断点没有捕捉到这个加载。
这意味着 Spring 是新的嫌疑人。 ConfigurationClassPostProcessor 中似乎有一些处理加载类以检查它们。这可能与我的问题有关。
ConfigurationClassBeanDefinitionReader 中的这些行导致读取 Lang 类:
else if (metadata.isAnnotated(Component.class.getName()) ||
metadata.hasAnnotatedMethods(Bean.class.getName())) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
return true;
}
特别是,metadata.hasAnnotatedMethods() 调用类上的getDeclaredMethods(),加载该类中所有方法的所有参数类。我猜这可能不是问题的结束,因为我认为这些类应该被卸载。 JVM 是否会出于不可知的原因缓存类实例?
最佳答案
好的,我已经解决了这个问题。本质上,它是与某些自定义扩展相关的 Spring 问题。如果有人遇到类似的事情,我会尝试逐步解释发生了什么。
首先,我们的项目中有一个自定义的BeanDefintionParser。此类具有以下定义:
private static class ControllerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
protected Class<?> getBeanClass(Element element) {
try {
return Class.forName(element.getAttribute("class"));
} catch (ClassNotFoundException e) {
throw new RuntimeException("Class " + element.getAttribute("class") + "not found.", e);
}
}
// code to parse XML omitted for brevity
}
现在,问题发生在所有 bean 定义都被读取并且 BeanDefinitionRegistryPostProcessor 开始启动之后。在这个阶段,一个名为 ConfigurationClassPostProcessor 的类开始查看所有 bean 定义, 搜索用 @Configuration 注释或具有 @Bean 方法的 bean 类。
在为bean 读取注解的过程中,它使用了AnnotationMetadata 接口(interface)。对于大多数常规 bean,使用一个名为 AnnotationMetadataVisitor 的子类。但是,在解析 bean 定义时,如果您重写了 getBeanClass() 方法以返回类实例,就像我们所做的那样,则会使用 StandardAnnotationMetadata 实例。当 StandardAnnotationMetadata.hasAnnotatedMethods(..) 被调用时,它会调用 Class.getDeclaredMethods(),这反过来会导致类加载器加载所有用作该类参数的类.以这种方式加载的类没有正确卸载,因此永远不会编织,因为这发生在 AspectJ 转换器注册之前。
现在,我的问题是我有这样一个类:
public class Something {
private Lang lang;
public void setLang(Lang lang) {
this.lang = lang;
}
}
然后,我有一个 Something 类的 bean,它使用我们的自定义 ControllerBeanDefinitionParser 进行了解析。这触发了错误的注解检测过程,进而触发了意外的类加载,这意味着 AspectJ 永远没有机会编织 Lang。
解决方案是不覆盖 getBeanClass(..),而是覆盖 getBeanClassName(..),根据文档,这是更可取的:
private static class ControllerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
protected String getBeanClassName(Element element) {
return element.getAttribute("class");
}
// code to parse XML omitted for brevity
}
今天的教训:不要重写 getBeanClass 除非你是认真的。实际上,除非您知道自己在做什么,否则不要尝试编写自己的 BeanDefinitionParser。
鳍。
关于java - AspectJ 加载时间编织器未检测到所有类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3619519/
我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog
我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build
我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s