Java中的动态代理

458 阅读1分钟

开局附上高手链接

JDK动态代理

Cglib动态代理

Jdk的动态代理,只能代理接口对象

原因是代理对象默认继承Proxy,然而Java语言特性只支持单继承,反编译可得如下代码

public final class UserDao$ProxyCode extends Proxy implements UserDao
  • 1.InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。
/*参数:
proxy - 在其上调用方法的代理实例
method - 对应于在代理实例上调用的接口方法的 Method 实例。 Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。
返回:
从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。*/
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
  • 2.Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法。

    /*参数:
    loader - 定义代理类的类加载器
    interfaces - 代理类要实现的接口列表
    h - 指派方法调用的调用处理程序
    返回:
    一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口*/
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
    

具体代码实现

public interface UserDao {//定义接口
    void save();
    void update();
    void delete();
    void find();
}
public class UserDaoImpl implements UserDao {//实现接口
    @Override
    public void save() {
        System.out.println("save-------");
    }

    @Override
    public void update() {
        System.out.println("update------");
    }

    @Override
    public void delete() {
        System.out.println("delete------");
    }

    @Override
    public void find() {
        System.out.println("find--------");
    }
}
//实现InvocationHandler接口的调用处理程序
//并封装一个获得代理对象的方法
public class MyJdkProxy implements InvocationHandler {
    private UserDao userDao;
    public MyJdkProxy(UserDao userDao){
        this.userDao = userDao;
    }
    public Object createProxy(){
        Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
                userDao.getClass().getInterfaces(),
                this
                );
        return proxy;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if ("save".equals(method.getName())){
            System.out.println("权限校验中......");
            return method.invoke(userDao, args);
        }
        if("find".equals(method.getName())){
            System.out.println("权限校验中......");
            return method.invoke(userDao, args);
        }
        return method.invoke(userDao, args);
    }
}
public class SpringDemo1 {
    @Test
    public void demo1(){
        UserDao userDao = new UserDaoImpl();

//        userDao.save();
//        userDao.delete();
//        userDao.update();
//        userDao.find();
        UserDao proxy = (UserDao) new MyJdkProxy(userDao).createProxy();
        proxy.save();
        proxy.find();
        proxy.update();
        proxy.delete();
    }
}
Cglib动态代理

使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

代理对象默认实现Factory接口,Jdk允许实现多个接口

反编译获得代码

//实现接口方式
public class ProductDao?EnhancerByCGLIB?40fd3cad implements ProductDao, Factory{
//...
}
//实现类的方式
public class ProductDao$ProductDao?EnhancerByCGLIB?58419779 extends ProductDao implements Factory {
//...
}
  • MethodInterceptor接口类似InvocationHandler
  • Enhancer类似Proxy类

具体代码实现

public class ProductDao {
    public void save() {
        System.out.println("save product-------");
    }

    public void update() {
        System.out.println("update product------");
    }

    public void delete() {
        System.out.println("delete product------");
    }

    public void find() {
        System.out.println("find product--------");
    }
}
public class MyCglibProxy implements MethodInterceptor {
    private ProductDao productDao;
    public MyCglibProxy(ProductDao productDao){
        this.productDao = productDao;
    }
    public Object createProxy(){
        //1 创建核心类
        Enhancer enhancer = new Enhancer();
        //2 设置父类
        enhancer.setSuperclass(productDao.getClass());
        //3 设置回调
        enhancer.setCallback(this);
        //4 生成代理
        Object proxy = enhancer.create();
        return proxy;
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        if("save".equals(method.getName())){
            System.out.println("权限校验中......");
            return methodProxy.invokeSuper(proxy, args);
        }
        return methodProxy.invokeSuper(proxy, args);
    }
}
public class SpringDemo2 {
    @Test
    public void demo1(){
        ProductDao productDao = new ProductDao();
        ProductDao proxy = (ProductDao) new MyCglibProxy(productDao).createProxy();
//        productDao.save();
//        productDao.delete();
//        productDao.find();
//        productDao.update();
        proxy.save();
        proxy.find();
        proxy.update();
        proxy.delete();
    }
}