JDK动态代理和CGLib动态代理简单演示

JDK1.3以后,Java提供了动态代理的技术,容许开发者在运行期间建立接口的代理实例。java

1、首先咱们进行JDK动态代理的演示。node

如今咱们有一个简单的业务接口Saying,以下:ide

package testAOP;
public interface Saying {
public void sayHello(String name);    
public void talking(String name);
}

一个简单的实现类SayingImpl,以下:测试

package testAOP;
public class SayingImpl implements Saying {
    @Override
    public void sayHello(String name) {
        // TODO Auto-generated method stub
        System.out.println(name + ":你们好啊!");
    }
    @Override
    public void talking(String name) {
        // TODO Auto-generated method stub
        System.out.println(name + ":个人意思是,咱们要努力建设和谐社会!");
    }
}

咱们要实现的是,在sayHello和talking以前和以后分别动态植入处理。this

JDK动态代理主要用到java.lang.reflect包中的两个类:Proxy和InvocationHandler.spa

InvocationHandler是一个接口,经过实现该接口定义横切逻辑,并经过反射机制调用目标类的代码,动态的将横切逻辑和业务逻辑编织在一块儿。代理

Proxy利用InvocationHandler动态建立一个符合某一接口的实例,生成目标类的代理对象。code

以下,咱们建立一个InvocationHandler实例:对象

package testAOP;

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

public class MyInvocationHandler implements InvocationHandler {

    private Object target;
    MyInvocationHandler(Object target){
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //目标方法前执行
        System.out.println("——————————————————————————");
        System.out.println("下一位请登台发言!");
        //目标方法调用
        Object obj = method.invoke(target, args);
        //目标方法后执行
        System.out.println("你们掌声鼓励!");
        return obj;
    }
}

下面是测试:blog

package testAOP;

import java.lang.reflect.Proxy;

public class JDKProxyTest {
    
    public static void main(String[] args) {
        // 但愿被代理的目标业务类
        Saying target = new SayingImpl();
        // 将目标类和横切类编织在一块儿
        MyInvocationHandler handler = new MyInvocationHandler(target);
        // 建立代理实例
        Saying proxy = (Saying) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),//目标类的类加载器
                target.getClass().getInterfaces(),//目标类的接口
                handler);//横切类
        proxy.sayHello("小明");
        proxy.talking("小丽");
    }
}

运行状况以下:

——————————————————————————
下一位请登台发言!
小明:你们好啊!
你们掌声鼓励!
——————————————————————————
下一位请登台发言!
小丽:个人意思是,咱们要努力建设和谐社会!
你们掌声鼓励!

使用JDK动态代理有一个很大的限制,就是它要求目标类必须实现了对应方法的接口,它只能为接口建立代理实例。咱们在上文测试类中的Proxy的newProxyInstance方法中能够看到,该方法第二个参数即是目标类的接口。若是该类没有实现接口,这就要靠cglib动态代理了。

CGLib采用很是底层的字节码技术,能够为一个类建立一个子类,并在子类中采用方法拦截的技术拦截全部父类方法的调用,并顺势植入横切逻辑。

 

2、接下来咱们进行cglib动态代理的演示。

首先咱们须要导包,我用的包是cglib-nodep-2.1_3.jar。

咱们首先建立一个代理建立器CglibProxy:

package testAOP.cglib;

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor{

    Enhancer enhancer = new Enhancer();
    public Object getProxy(Class clazz) {
        //设置须要建立的子类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //经过字节码技术动态建立子类实例
        return enhancer.create();
    }
    @Override
    public Object intercept(Object obj, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("——————————————————————————");
        System.out.println("下一位请登台发言!");
        //目标方法调用
        Object result = proxy.invokeSuper(obj, args);
        //目标方法后执行
        System.out.println("你们掌声鼓励!");
        return result;
    }    
}

而后进行测试:

package testAOP.cglib;

import testAOP.Saying;
import testAOP.SayingImpl;

public class CglibProxyTest {

    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        //经过动态生成子类的方式建立代理类
        Saying target = (Saying) proxy.getProxy(SayingImpl.class);
        target.sayHello("小明");
        target.talking("小丽");
    }
}

结果与JDK动态代理没有任何区别。

CGLib动态代理能代理类和接口,可是不能代理final类,也是有必定局限性。

JDK动态代理和CGLib动态代理都是运行时加强,经过将横切代码植入代理类的方式加强。与此不一样的是AspectJ,它可以在经过特殊的编译器在编译时期将横切代码植入加强,这样的加强处理在运行时候更有优点,由于JDK动态代理和CGLib动态代理每次运行都须要加强。

相关文章
相关标签/搜索