欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java动态代理和cglib动态代理示例分享

程序员文章站 2024-02-24 18:42:40
java动态代理类可以分为两种。 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 动态代理:在程序运行时,...

java动态代理类可以分为两种。

静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。

动态代理:在程序运行时,运用反射机制动态创建而成。


一、首先我们进行java动态代理的演示。

现在我们有一个简单的业务接口saying,如下:

复制代码 代码如下:

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之前和之后分别动态植入处理。

jdk动态代理主要用到java.lang.reflect包中的两个类:proxy和invocationhandler.

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

proxy利用invocationhandler动态创建一个符合某一接口的实例,生成目标类的代理对象。

如下,我们创建一个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;
    }
}

下面是测试:

复制代码 代码如下:

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采用非常底层的字节码技术,可以为一个类创建一个子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势植入横切逻辑。

二、接下来我们进行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动态代理没有任何区别。

jdk动态代理和cglib动态代理都是运行时增强,通过将横切代码植入代理类的方式增强。与此不同的是aspectj,它能够在通过特殊的编译器在编译时期将横切代码植入增强,这样的增强处理在运行时候更有优势,因为jdk动态代理和cglib动态代理每次运行都需要增强。