java - 如何使用 AspectJ 在 AOP 中为每个类、每个对象和每个方法/源位置部分创建一个方面
问题描述
我想为每个类、每个对象和每个方法/源位置部分创建一个方面实例。
更具体地说:
- 有些值只从类到类改变,但每个类只需要计算一次,因此它们需要每类推导一次。例如,存储
Class
将是每个类,也是对Logger
特定类的引用以进行日志记录。 - 有些值因方法而异,但每个方法只需要计算一次,因此每个方法都需要推导一次。例如,方法签名将是每个类的每个方法。此数据不会因对象实例或调用而改变。
- 有些值从实例/对象变为实例/对象,但每个实例/对象只需要计算一次,因此每个实例/对象需要推导一次。例如对象 ID,这将取决于实例。
- 有些值会随着对象的变化而变化,但每个对象的每个字段或方法只需要计算一次,因此它们需要每个对象的每个字段或方法推导出一次。例如,方法的调用计数,这将取决于方法和对象。
- 一些值因调用而异,因此需要为每次调用推导/计算它们。例如在 AspectJ 中获取方法参数。这取决于方法、对象和调用。
我正在尝试创建存储这些推导/计算值的方面。为了在内存和计算方面不产生超过所需的东西。这如何在 Eclipse AspectJ AOP 中实现?
到目前为止,我一直在尝试创建这样的层次结构:
aspect Base {
// Singleton - data items for the whole program computed and stored once
// This is shared across all the objects in the application regardless of the class
protected pointcut executionJoinPoints(): !within(Base+) && execution (* *.*(..));
}
aspect PerClass extends Base perthis(executionJoinPoints()) {
// Per class - store class-specific data computed and stored once per class
// Since this is class-specific, need to know what class this corresponds to
// This is shared across all the objects of the same class
}
aspect PerMethodPerClass extends PerClass percflow(executionJoinPoints()) {
// Per method - store method specific data computed and stored once per method as fields
// Since this is method-specific, need to know what method this corresponds to
// This is shared across all the objects of the same class
}
aspect PerObject extends PerMethodPerClass perthis(executionJoinPoints()) {
// Per object/instance - store object/instance-specific data computed and stored once per object
// Since this is object/instance-specific, need to know what object/instance this corresponds to
// This is specific to the object/instance
}
aspect PerMethodPerObject extends PerObject percflow(executionJoinPoints()) {
// Per method per object - store method specific data computed and stored once per method as fields for every object instance
// Since this is method-specific, need to know what method this corresponds to and also what object this corresponds to
// This is specific to the object/instance and particular method
}
public aspect PerCall extends PerMethodPerInstance {
// Per call - handle data which change from call to call
// This is specific to the call or invocation or execution
}
我正在尝试实施:
- 记录和跟踪
- 程序执行的度量和统计数据收集
使用 AspecJ AOP。对于统计数据,我收集每个类、每个对象和每个方法/源位置部分都需要一个方面实例来存储和收集相关数据。
例如,与方法相关的统计数据将被计算并存储在一个PerMethod
方面中。此外,查找特定于方法的计数器可访问实例比在大型数据结构中查找它更容易。这里需要的是每个方法都实例化一次方面。对于类、对象等也是如此。
收集执行统计信息会产生一些开销,但在这样做时,我试图将其保持在最低限度,因此为什么我想要每个案例的特定方面。
我要求它学习如何在 AspectJ 中执行此操作,而不是尝试解决特定问题。一旦我尝试实现它,可能会弹出特定的问题,我可以分享我尝试过的更具体的示例以及它产生的错误或问题。
解决方案
很抱歉写这个作为答案,但评论太长了。
这个问题的问题在于,尽管进行了广泛的解释,但您只解释了您希望如何在技术上做某事,甚至没有说明您要解决的问题是什么。这使得这个问题成为XY 问题的一个很好的例子。
- 你的方面是做什么的?
- 您是否遇到内存或性能问题?
- 您确定不是您的广泛的包罗万象的切入点与建议代码本身相结合 - 在之前的问题中,您想详细记录每个方法执行的所有内容,模拟某种调试器 - 是问题吗?
- 你有问题吗?如果是这样,你没有说明。您可能只是在进行过早的优化。
您正在尝试节省内存和 CPU 周期,我从您的问题中得到了这一点。
- 您是否知道通过尝试这样做您是通过
per...
子句创建许多方面实例而不是使用默认的 AspectJ 单例方面实例化模型? - 你是否衡量过这是否会让事情变得更好,而不是更糟?
实际上,您的问题并没有提出真正的问题,您所展示的方面的层次结构完全没有做任何事情。所以这样的问题格式与 StackOverflow 不兼容。这是一个问答平台,不是论坛。我通过实际询问而不是为您的问题提出解决方案来回答已经是它的症状。有意见的辩论正是 SO 不适合的。所以就像我之前在其他问题中所说的那样:提问的最佳方式是提供MCVE和清晰的问题描述,其他人可以运行代码并重现您的问题。
更新:正如您在 AspectJ 手册中看到的,有以下方面实例化类型:
- 单身人士
- 每个对象(
perthis()
与pertarget()
例如不同的call()
切入点但应该相同execution()
) - 每个控制流 (
percflow()
vspercflowbelow()
) - 每个类型(
pertypewithin()
,在此处描述)
请注意,“每个控制流”与“每个方法”不同。如文档所述,每次进入某个控制流时都会创建一个方面实例,例如每次执行一个方法时。如果相同的方法执行 12,345 次,则将创建 12.345 个方面实例。因此,如果您希望收集每个方法的统计信息,最好将信息存储在相应类的每个类型方面实例中。对于您的“每次通话”要求,我认为“每个控制流”的建议是合适的。
现在我们完成了。就像我说的,如果你想在这里讨论你的应用程序设计想法,那就错地方了。因此,我将在此停止回复,并等待您使用 MCVE 提出具体的新问题,这些问题可以清楚正确地回答,而不是引发讨论。我现在提供了尽可能多的帮助,超过了我应该提供的帮助,因为这个问题实际上应该作为题外话 IMO 关闭。
祝你有趣的项目好运。如果您需要更多咨询,我也将其作为日常工作,您当然可以雇用我。;-)
否则,我想鼓励您通过实施某些事情而不是在这里提出一大堆理论问题(我现在已经回答了其中的 3 个)来创建可验证的事实,然后看看您的想法是否有效。你似乎喜欢推理。思考是好的,做事也是。使用两者,您将取得更大的进步并迭代地(in-)验证您的想法。
推荐阅读
- python - 发生 ConnectionError 时程序不会退出,但发生错误时会冻结
- reactjs - 我的 reactJS 组件中的 React-redux 状态未定义错误
- python-3.x - inbuild sum 和 pd.Series.sum 函数的结果之间的差异
- mongodb - AWS ec2 上 mongodb 4.2.8 中的连接问题
- gnuplot - 在 GNUPLOT 中将鼠标悬停在函数上时显示 x 和 y 值的标签,可能还有其他值
- javascript - 如何在正则表达式中传递变量
- spring-boot - 在转换方法中从 lambda 返回 null 或可为 null 的东西 - Webflux(Intellij 警告)
- java - Kotlin 函数参数:如何定义一个可以有尾随 lambda 或接口作为参数的函数?
- python - 为什么在这种情况下,pandas 中 .mean() 方法的轴是相反的?
- javascript - 如何从 Jest 手动模拟中检查默认导出功能