• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Java > [译]深入字节码操作:使用ASM和Javassist创建审核日志

[译]深入字节码操作:使用ASM和Javassist创建审核日志

作者:liken的专栏 字体:[增加 减小] 来源:互联网 时间:2017-07-23

liken的专栏通过本文主要向大家介绍了javassist,javassist.jar,javassist 3.7.ga.jar,javassist下载,javassist.jar下载等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

深入字节码操作:使用ASM和Javassist创建审核日志

原文链接:https://blog.newrelic.com/2014/09/29/diving-bytecode-manipulation-creating-audit-log-asm-javassist/

在堆栈中使用Spring和Hibernate,您的应用程序的字节码可能会在运行时被增强或处理。 字节码是Java虚拟机(JVM)的指令集,所有在JVM上运行的语言都必须最终编译为字节码。 操作字节码原因如下:

  • 程序分析:
    • 查找应用bug
    • 检查代码复杂性
    • 查找特定注解的类
  • 类生成:
    • 使用代理从数据库中懒惰加载数据
  • 安全性
    • 特定API限制访问权限
    • 代码混淆
  • 无Java源码类转换
    • 代码分析
    • 代码优化
  • 最后,添加日志

有几种可用于操作字节码的工具,从非常低级的工具(如需要字节码级别工作的ASM)到诸如AspectJ等高级框架(允许编写纯Java)。

本博文,我将演示分别使用Javassist和ASM实现一种审计日志的方法。

审计日志例子

假定我没有如下代码:

public class BankTransactions {
    public static void main(String[] args) {
    BankTransactions bank = new BankTransactions();
    for (int i = 0; i < 100; i++) {
        String accountId = "account" + i;
        bank.login("password", accountId, "Ashley");
        bank.unimportantProcessing(accountId);
        bank.withdraw(accountId, Double.valueOf(i));
    }
    System.out.println("Transactions completed");
    }
}

我们要记录重要的操作以及关键信息以确定操作。 以上,我将确定登录退出的重要动作。 对于登录,重要信息将是帐户ID和用户。 对于退出,重要信息将是帐户ID和撤回的金额。 记录重要操作的一种方法是将日志记录语句添加到每个重要的方法,但这将是乏味的。 相反,我们可以为重要的方法添加注释,然后使用工具来注入日志记录。 在这种情况下,该工具将是一个字节码操作框架。

@ImportantLog(fields = { "1", "2" })
public void login(String password, String accountId, String userName) {
    // login logic
}
@ImportantLog(fields = { "0", "1" })
public void withdraw(String accountId, Double moneyToRemove) {
    // transaction logic
}

@ImportantLog注释表示我们要在每次调用该方法时记录一条消息,而@ImportantLog注释中的fields参数表示应记录的每个参数的索引位置。 例如,对于登录,我们要记录第1位和第2位的输入参数。它们是accountId和userName。 我们不会记录第0位的密码参数。

使用字节码和注释来执行日志记录有两个主要优点:

  1. 日志记录与业务逻辑分离,这有助于保持代码清洁和简单。
  2. 在不修改源代码的情况下,轻松删除审核日志记录。

在哪里实际修改字节码?

我们可以使用1.5中引入的核心Java功能来操纵字节码。 此功能称为Java代理。
要了解Java代理,让我们来看一下典型的Java处理流程。

使用包含我们的main方法的类作为输入参数执行命令java。 这将启动Java运行时环境,使用classloader来加载输入类,并调用该类的main方法。 在我们具体的例子中,调用了BankTransactions的main方法,这将导致一些处理发生,并打印“完成交易”。

现在来看一下使用Java代理的Java进程。

命令java运行两个输入参数。第一个是JVM参数-javaagent,指向代理jar。第二个是包含我们主要方法的类。javaagent标志告诉JVM首先加载代理。 代理的主类必须在代理jar的清单中指定。 一旦类被加载,类的premain方法被调用。 这个premain方法充当代理的安装钩子。 它允许代理注册一个类变换器。 当类变换器在JVM中注册时,该变换器将在类加载到JVM前接收每个类的字节。 这为类变换器提供了根据需要修改类的字节的机会。 一旦类变换器修改了字节,它将修改的字节返回给JVM。 这些字节接着由JVM验证和加载。

在我们具体的例子中,当BankTransaction加载时,字节将首先进入类变换器进行潜在的修改。修改后的字节将被返回并加载到JVM中。 加载完之后,调用类中的main方法,进行一些处理,并打印“事务完成”。

让我们来看看代码。 下面我有代理的premain方法:

public class JavassistAgent {
    public static void premain(String agentArgs, Instrumentation inst) {
    System.out.println("Starting the agent");
    inst.addTransformer(new ImportantLogClassTransformer());
    }
}

premain方法打印出一个消息,然后注册一个类变换器。 类变换器必须实现方法转换,加载到JVM中的每个类都会调用它。它以该类的字节数组作为方法的输入,然后返回修改后的字节数组。如果类变换器决定不修改特定类的字节,则可以返回null。

public class ImportantLogClassTransformer implements ClassFileTransformer {
    public byte[] transform(ClassLoader loader, String className,
    Class classBeingRedefined, ProtectionDomain protectionDomain,
    byte[] classfileBuffer) throws IllegalClassFormatException {
    // manipulate the bytes here
        return modified bytes;
    }
}

现在我们知道在哪里修改一个类的字节,接着需要知道如何修改字节。

如何使用Javassist修改字节码?

Javassist是一个具有高级和低级API的字节码操作框架。我将重点关注高级的面向对象的API,首先从Javassist中的对象的解释开始。接下来,我将实现审核日志应用程序的实际代码。

Javassist使用CtClass对象来表示一个类。 这些CtClass对象可以从ClassPool获得,用于修改Classes。ClassPool是一个基于HashMap实现的CtClass对象容器,其中键是类名称,值是表示该类的CtClass对象。默认的ClassPool使用与底层JVM相同的类路径。因此,在某些情况下,可能需要向ClassPool添加类路径或类字节。

类似于包含字段,方法和

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • [译]深入字节码操作:使用ASM和Javassist创建审核日志

相关文章

  • 2017-05-28Java中ArrayList和LinkedList之间的区别_动力节点Java学院整理
  • 2017-05-28Spring Boot使用Druid进行维度的统计和监控
  • 2017-05-28Java高级特性(基础)
  • 2017-09-06个人模拟面试之基础知识+部分线程问题
  • 2017-05-28详解Spring Boot中使用AOP统一处理Web请求日志
  • 2017-05-28springMVC4之强大类型转换器实例解析
  • 2018-11-21JBoss arjuna TransactionReaper不回滚超时
  • 2017-05-28详解SpringMVC注解版前台向后台传值的两种方式
  • 2017-05-28详谈java 堆区、方法区和栈区
  • 2017-05-28java方法重写和super关键字实例详解

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • java数据结构与算法之冒泡排序详解
    • Java本地缓存的实现代码
    • java 对文件夹目录进行深度遍历实例代码
    • java服务端微信APP支付接口详解
    • SWT(JFace) 体验之FontRegistry
    • Java查找 List 中的最大最小值实例演示
    • 深入理解java泛型详解
    • Java 回调函数详解及使用
    • Spring Boot中Redis数据库的使用实例
    • 详解Spring中bean实例化的三种方式

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有