java - 通过 aspectJ 和 byte-buddy 代理检测编织类
问题描述
我想验证代码是由 aspectJ 编织的。我听说过的一种方法是使用 byte-buddy 库中的代理。不幸的是,我完全是绿色的,我不知道我能做什么。
我尝试过用JADE搭配agent,但是byte-buddy对我自己比较友好,我觉得比较合适。
为了验证该方法,我创建了一个带有 MySQL 连接的简单 springboot 应用程序并添加了一些 aspectJ 代码。我尝试使用 Spring AOP,但 AOP 无法读取私有方法,所以我决定用 aspectJ 提供我的想法。
我已经使用了另一个方面来定义 joinPoints 并抛出异常,但这很困难,并且需要大量工作,结果很低。
您对使用字节伙伴检测aspectJ的代理的方法或实现有任何想法吗?
解决方案
首先回答您的评论:
我想对不受信任的代码有更多的经验。例如,如果我在 Java 中获得了一个大项目,然后我得到了一些由 AspectJ 创建的带有更改的不受信任的插件,那么我更愿意知道如何检查我的类是否受到 AspectJ 的保护,或者 AspectJ 是否只是编织到我的类中。
对于 AspectJ,有两种情况:
编译时编织
- 您的应用程序不使用 AspectJ,在您的 Maven 构建中没有使用 AspectJ Maven 插件,或者在您的 Gradle 构建中没有类似的东西:即使您的第三方库在类路径中,也没有任何东西被编织到您自己的代码中。怎么可能?没有 AspectJ 编译器。
- 您的应用程序使用 AspectJ 编译器:即使第三方库位于类路径中,也不会将任何方面编织到您自己的代码中,因为您必须显式地将库放在方面路径上才能实现这一点。顺便说一句,如果第三方库是方面增强的,它将依赖于 AspectJ 运行时aspectjrt.jar,否则它将无法工作。即使运行时被隐藏到另一个 JAR 中,您自己的代码仍然不会发生任何事情。
加载时编织
- 您的应用程序不使用 LTW:显然不会发生任何事情,如果您没有使用活动编织代理启动 JVM,则其他 JAR 的任何方面都无法编织到您的代码中。
- 您的应用程序使用 LTW:您需要提供一个aop.xml文件,在那里您可以显式列出您想要应用的方面,哪些目标类或包要包含在编织中或从编织中排除,打开
-showWeaveInfo
顺序也可以在控制台上查看哪些方面被编织到哪些连接点中。但是有一个警告:如果 AspectJ 编织器在类路径中找到多个aop.xml或aop-ajc.xml文件,它将在概念上合并它们。即,如果第三方库带有这样的文件,它将被合并到您自己的文件中,如AspectJ 开发指南中所述(在页面上搜索“几个配置文件”)。因此,这可能会导致一些不良副作用。如果要检查第三方库,最简单的做法是分别扫描 JAR 中是否存在aop.xml或aop-ajc.xml。然后,您可以查看这些文件的内容(如果有),并轻松评估它们对您的代码可能产生的影响。但是仅检查-showWeaveInfo
应用程序启动时的输出也可以揭示是否将不需要的方面编织到您自己的代码中。
所以实际上你不需要扫描类文件中的任何东西来检测 AspectJ 标记,但如果你绝对希望这里是你可以做的事情:
大多数 AspectJ 编织的类都包含字段或方法(可以是静态的或非静态的、私有的或公共的),ajc$
它们的名称中有某处,通常在开头。这只是一种启发式方法,但是,嘿——不管怎样,对吧?
- 如果我说“大多数类”,我的意思是在某些情况下,如果一个方面仅使用 ITD 来使一个类实现接口、引入新方法或公共字段,那么该类将只获得新元素但没有特定于 AspectJ 的代码. 但是它们只是普通的类,没有横切的建议代码或任何可能影响您自己的应用程序的东西。
- 如果您找到这样的成员或字段,则表明您找到了由方面增强的类(即使在带有额外aop.xml的 LTW 场景中也不会影响您自己的类)或方面本身,因为它们也包含相同的标记加上您可以扫描的其他一些东西。
那么如何扫描那些第三方类文件呢?
- 命令行:
javap -p path/to/MyClass.class | grep 'ajc[$]'
- 用于扫描已加载到(测试或检查)应用程序中的类的 Java 代码:
package de.scrum_master.aspect;
import java.lang.reflect.Member;
import java.util.stream.Stream;
public class AspectJDetector {
public static boolean hasAspectJMarker(Class<?> clazz) {
return Stream.concat(
Stream.of((Member[]) clazz.getDeclaredMethods()),
Stream.of((Member[]) clazz.getDeclaredFields())
)
.filter(member -> member.getName().contains("ajc$"))
.findFirst()
.isPresent();
}
}
只需致电hasAspectJMarker(MyClassOfInterest.class)
您要检查的每个课程。如果您发现 AspectJ 增强的类,则无需担心。仅当您找到可能存在的方面时。但正如我上面所说:这将更容易通过该 JAR 中的aop.xml检测到。XML 文件甚至会通过 显式列出各个方面<aspect name="com.MyAspect"/>
,这基本上是不费吹灰之力。
推荐阅读
- stripe-payments - 将 Stripe Payment Request 按钮显示为 Google Pay 按钮
- react-native - 如何解决在 React Native Web 应用程序中导入 ChatBot 时出现意外令牌错误
- sql - 显示另一个表不包含的表中的行
- wpf - WPF 无法从代码访问 DependencyProperty
- python - 使用 microsoft graph 更新电子邮件类别
- typescript - 如何使用语音识别填充所有离子表单字段?
- python - Python 错误:[ZeroDivisionError:除以零]
- amazon-s3 - presto 在 S3 中将多行映射到单个文件的选项是什么?
- javascript - moment.js 支持哪种格式的区域缩写
- scala - 比较和计算表中的值 - 使用 Scala 的 Spark