java 动态代理

动态代理的实现可以通过 jdk 自带的 动态代理的支持实现,也可以通过 cglib 来实现。jdk 的动态代理是基于接口实现的,只有实现了接口的实现类 才可以被代理。而 cglib 是通过对实现类进行继承来实现,也就是通过生成被代理的实现类的子类,这里的实现类可以不实现某一接口。因采用继承方式,所以对于final 的方法是不能够进行代理的。至于性能问题,网上有文说:

 

有研究表明, CGLib 所创建的动态代理对象的性能依旧比 JDK 的所创建的代理对象的性能高不少(大概 10 倍)。而 CGLib 在创建代理对象时性能却比 JDK 动态代理慢很多(大概 8 倍),所以对于 singleton 的代理对象或者具有实例池的代理,因为不需要频繁创建代理对象,所以比较适合用 CGLib 动态代理技术,反之适合用 JDK 动态代理技术。


对于此两种方式的实现 demo 如下:

1: jdk 的动态代理


第一步:定义接口

package com.zonqian.proxy.test.tt_1;

public interface Subject {
    abstract public void request();
}


第二步:定义接口实现

package com.zonqian.proxy.test.tt_1;

public class RealSubject implements Subject {
    public RealSubject() {
    }

    public void request() {
        System.out.println("From real subject.");
    }
}


第三步:设计动态代理

package com.zonqian.proxy.test.tt_1;

import java.lang.reflect.Method;

import java.lang.reflect.InvocationHandler;

public class DynamicSubject implements InvocationHandler {
    private Object sub;

    public DynamicSubject() {
    }

    public DynamicSubject(Object obj) {
        sub = obj;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before calling " + method);
        method.invoke(sub, args);
        System.out.println("after calling " + method);
        return null;
    }
}

这里通过构造函数来引用被注入的实现类。

 

第四步:编写测试客户端

package com.zonqian.proxy.test.tt_1;

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

public class Client {
    static public void main(String[] args) throws Throwable {
        RealSubject rs = new RealSubject(); // 在这里指定被代理类
        InvocationHandler ds = new DynamicSubject(rs); // 初始化代理类
        Class cls = rs.getClass();
       
        // 以下是分解步骤
        /*
         *
         * Class c =
         * Proxy.getProxyClass(cls.getClassLoader(),cls.getInterfaces()) ;
         *
         * Constructor ct=c.getConstructor(new
         * Class[]{InvocationHandler.class});
         *
         * Subject subject =(Subject) ct.newInstance(new Object[]{ds});
         */

        // 以下是一次性生成
        Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(), cls
                .getInterfaces(), ds);
        subject.request();
    }
}

 

 

2: cglib 的动态代理实现

 

第一步:定义被代理的实现类

package com.zonqian.proxy.test.tt_3;

public class ForumServiceImpl {

    public void removeTopic(int topicId) {

        System.out.println("模拟删除Topic记录:" + topicId);
        try {
            Thread.currentThread().sleep(20);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    public void removeForum(int forumId) {

        System.out.println("模拟删除Forum记录:" + forumId);
        try {
            Thread.currentThread().sleep(40);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
}

 

第二步: 设计动态代理

package com.zonqian.proxy.test.tt_3;

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 {
    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class clazz) {
        enhancer.setSuperclass(clazz); // 设置需要创建子类的类
        enhancer.setCallback(this);
        return enhancer.create(); // 通过字节码技术动态创建子类实例
    }

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
            throws Throwable {
//        PerformanceMonitor.begin(obj.getClass().getName() + "." + method.getName());
        System.out.println(obj.getClass().getName() + "." + method.getName() + " begin");
        Object result = proxy.invokeSuper(obj, args); // 通过代理类调用父类中的方法
//        PerformanceMonitor.end();
        System.out.println(obj.getClass().getName() + "." + method.getName() + " end /n");
        return result;
    }
}

 

第三步: 编写测试客户端

package com.zonqian.proxy.test.tt_3;

public class TestForumService {
    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        // ① 通过动态生成子类的方式创建代理对象
        ForumServiceImpl forumService = (ForumServiceImpl) proxy.getProxy(ForumServiceImpl.class);
        forumService.removeForum(10);
        forumService.removeTopic(1023);
    }
}

 

关于cglib动态代理的安全性:

all generated classes have the same protection domain (signer and codebase) as cglib itself and can be used in WS or by RMI application with security manager.


cglib 采用 字节码增强 来实现,其实现依赖于 asm 包,执行时需要导入该jar包。


http://cglib.sourceforge.net/howto.html  这里有使用 cglilb 的几个 demo,也可以参考下。


关于 cglib 的应用在许多开源项目,如: spring 和 hibernate 中都有相关的应用。

此文的内容 demo 也来源与网络的一些博客记载,此处重复记载,已被自己后查。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值