java动态代理

静态代理

即创建一个代理类,代理类中创建被代理类的对象,代理类对外提供方法a调用,方法a中代理类调用被代理类的方法b,并在方法b前后加一些操作,实现代理增强效果。静态代理的缺点是不灵活,每加一个方法都要加一个代理方法。

 

字节码增强

字节码增强即在运行阶段对已生成的字节码对象从内存中读取出来,通过一些技术修改字节码对象增强其功能。

原理:

1.在内存中获取原始的字节码,然后通过一些开源项目(ASM,CGBLIb,javassist)等修改它的byte[]数组,得到一个新的byte[]数组。 2.将这个新的byte[]数组写到PermGen区域,加载它或者替换原来的Class字节码。

 

动态代理

在程序运行时,通过字节码增强技术,为一个类生成代理对象,这个代理对象实现了在被代理对象执行方法前后添加一些操作实现增加,比如为一个对象的方法统一在方法访问前增加权限校验、打日志等。

动态代理的方式:

1. jdk自带的动态代理实现,通过创建一个代理处理类实现InvocationHandler,在invoke方法中实现方法增强,通过Proxy.newProxyInstance并传入代理处理类的方式返回代理对象,实现动态代理。这种形式jdk原生支持,不用引入外部jar包,且jdk8以上效率比cglib高。缺点是被代理类必须是实现了接口,必须实现接口与jdk动态代理的实现方式有关,由于返回的代理对象要可以强转成被代理类,所以代理对象要么是成为被代理类的子类,要么被代理类改成用接口接收代理类,代理类实现接口从而达到可以强转。jdk自带的动态代理就是通过实现接口的形式,代理类实现接口,因为java只能单继承,代理类本身需要继承Proxy,需要接收invokeHandler和使用proxy中的invoke方法,所以只能通过实现接口获取被代理类的方法信息和实现强转。mybatis就是通过jdk动态代理方式方式实现字节码增强。如下展示了个简单实例。

public interface Say {
    Integer say(String a);
}

public class SayHello implements Say {

    public Integer say(String a) {
        System.out.println(a+" hello");
        return 2;
    }

}

public class MyHandler implements InvocationHandler {

    Object o;

    Object bind(Object o){
        this.o = o;
        return java.lang.reflect.Proxy.newProxyInstance(o.getClass().getClassLoader(),o.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("之前---");
        method.invoke(o,args);
        System.out.println("之后---");
        return 1;
    }
}

public class Test {

    public static void main(String[] args) {
        Say s = (Say) new MyHandler().bind(new SayHello());
        s.say("name");
    }
}

2. cglib动态代理

开源的动态代理框架,基于asm框架实现(ASM是一个轻量级的类库,用于动态修改字节码文件,但需要涉及到JVM的操作和指令比较复杂),spring aop采用的代理方式之一。原理通过从内存中加载出被代理类的字节码信息,继承为被代理类的子类实现,不需要被代理类实现了接口。spring通过判断被代理类是否有实现接口,决定使用jdk动态代理还是cglib

public class CglibProxy implements MethodInterceptor {

    private Object object;

    public Object bind(Object object){
        this.object = object;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(object.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib之前--");
        Object result = method.invoke(object,objects);
        System.out.println("cglib之后--");
        return result;
    }
}
JDK动态代理是实现了被代理对象的接口,Cglib是继承了被代理对象。
JDK调用代理方法,是通过反射机制调用,Cglib是通过FastClass机制直接调用方法,Cglib执行效率更高。

3.Javassist动态代理

Javassist是一个开源的分析、编辑和创建Java字节码的类库,dubbo的动态代理默认就是通过javassist实现的

你可能感兴趣的:(Java基础)