AOP 的一些实现方法

前段时间去面试,被问到了AOP的原理,当时回答是通过代理,还自信满满的。原来还是存在其他的一些方法的。趁这段时间,离职之际冲冲电,稍微挖一下。



package demo.aop;

public interface ActionI {
public void doSth();
}




package demo.aop;

public class ActionImpl implements ActionI {

@Override
public void doSth() {
System.out.println("doing sth");
}

}



1.通过装饰器方法

package demo.aop;

public class ActionDecorator implements ActionI {
private ActionI action;

public ActionDecorator(ActionI action) {
this.action = action;
}

@Override
public void doSth() {
System.out.println("doSth invoke start");
action.doSth();
System.out.println("doSth invoke end");
}

public static void main(String[] args) {
ActionI action = new ActionDecorator(new ActionImpl());
action.doSth();

}
}



输出:
doSth invoke start
doing sth
doSth invoke end


使用装饰器的时候,如果要切入多个方法的时候,装饰器内就需要手懂编写同样多个方法。这种方法是显然是不够动态和灵活的。

2.使用Proxy代理


package demo.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ActionInvocationHandler implements InvocationHandler {

private ActionI action;

public ActionInvocationHandler(ActionI action){
this.action = action;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Log.info(method.getName()+" start");
method.invoke(action, args);
Log.info(method.getName()+" end");
return null;
}


public static void main(String[] args){
ActionI action = (ActionI)Proxy.newProxyInstance(ActionI.class.getClassLoader(), new Class[] { ActionI.class },
new ActionInvocationHandler(new ActionImpl()));
action.doSth();
}

}




输出
doSth start
doing sth
doSth end

不足之处在于:代理是面向接口的,代理的对象必须是对一个接口的实现。代理是通过反射机制实现的,效率不高。

相较以上两种方法,改变java方法的更直接的方法是修改字节码
Java 规范详细说明了 class 文件的格式,直接编辑字节码确实可以改变 Java 类的行为。
3.hook
启动时往 Java 虚拟机中挂上一个用户定义的 hook 程序,可以在装入特定类的时候改变特定类的字节码,从而改变该类的行为。但是其缺点也是明显的:

Instrument 包是在整个虚拟机上挂了一个钩子程序,每次装入一个新类的时候,都必须执行一遍这段程序,即使这个类不需要改变。
直接改变字节码事实上类似于直接改写 class 文件,无论是调用 ClassFileTransformer. transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer),还是 Instrument.redefineClasses(ClassDefinition[] definitions),都必须提供新 Java 类的字节码。也就是说,同直接改写 class 文件一样,使用 Instrument 也必须了解想改造的方法相对类首部的偏移量,才能在适当的位置上插入新的代码。

尽管 Instrument 可以改造类,但事实上,Instrument 更适用于监控和控制虚拟机的行为。

4.asm
Java 字节码操控框架,能动态生成类或者增强既有类的功能。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值