java 类增强机制

本文详细介绍了Java类增强的多种方式,包括静态代理、编译期织入、加载时织入(LTW)和运行时织入。重点讨论了LTW的实现,包括自定义类加载器和使用instrument机制。文章还探讨了Instrumentation对象的获取以及attach的实现原理,最后提到了Java动态代理和cglib作为运行时织入的工具。
摘要由CSDN通过智能技术生成

前言

对类的增强有多少种方式?我们首先想一下一个类的生命周期,从编码到程序运行结束:
类生命周期.jpg
对类的增强,目的是为了在使用的时候能够在类原有的行为上进行增强,所以编码一直到使用中的几乎每个环节都可以对类进行增强,主要有以下几种方式:

  1. 静态代理
  2. 编译期织入:aspectJ
  3. 加载时织入:1. 自定义classLoader;有容器能力;2. instrumention 动态attach
  4. 运行时织入:动态代理
    类增强时机.png

1. 静态代理

静态代理是最简单也是最容易理解的一种方式,只需要在编码的时候创建手动创建代理类调用即可,缺点也很明显,灵活性太差,代理的代码很难复用,编码结束之后类的增强就没有补充的可能性了。

// 接口
public interface NameService {
    void printName(String name);
}
// 实现类
public class NameServiceImpl implements NameService {
    @Override
    public void printName(String name) {
        System.out.println(name);
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
// 代理类
public class NameServiceProxy implements NameService {

    private NameService target;

    public NameServiceProxy(NameService nameService){
        this.target = nameService;
    }

    @Override
    public void printName(String name) {
        long cost = System.currentTimeMillis();
        target.printName(name);
        cost = System.currentTimeMillis() - cost;
        System.out.println("method printName cost is "+ cost);
    }
}
// 调用
public class Main {

    public static void main(String[] args) throws Exception {
        NameService nameService = new NameServiceProxy(new NameServiceImpl());
        nameService.printName("tiang");
    }
}
// 结果
tiang
method printName cost is 1002

2. 编译期织入

需要特殊的编译器,在将java文件编译成字节码的时候进行增强,编译后的字节码本身就包含了增强的结果。

  1. 服务编码
public class NameService {
    public void printName(String name){
        System.out.println(name);
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  1. 编写切面文件WasteTime.aj
public aspect WasteTime {

    pointcut print():execution(void NameService.printName(..));

    void around(): print(){
        long cost = System.currentTimeMillis();
        proceed();
        cost = System.currentTimeMillis() - cost;
        System.out.println("method printName cost :" + cost);
    }
}

  1. 采用AspectJ编译器编译后执行
public class Main {
    public static void main(String[] args) {
        NameService nameService = new NameService();
        nameService.printName("tiang");
    }
}

运行结果

tiang
method printName cost :1000
  1. 将编译后的NamService.class文件进行反编译
public class NameService
{
    public void printName(final String name) {
        printName_aroundBody1$advice(this, name, WasteTime.aspectOf(), null);
    }
    // 原方法
    private static final /* synthetic */ void printName_aroundBody0(final NameService ajc$this, final String name) {
        System.out.println(name);
        try {
            Thread.sleep(1000L);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    // 增强的代码与原方法耦合
    private static final /* synthetic */ void printName_aroundBody1$advice(final NameService ajc$this, final String name, final WasteTime ajc$aspectInstance, final AroundClosure ajc$aroundClosure) {
        long cost = System.currentTimeMillis();
        printName_aroundBody0(ajc$this, name);
        cost = S
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值