JDK动态代理实现

JDK动态代理实现

这里我们依赖Proxy类(Java代理类)里面的newProxyInstance()方法来创建代理对象来实现JDK动态代理

  • java.lang.reflect.Proxy类

static object newProxyInstance(ClassLoader loader), Class<?> [] interfaces, InvocationHandler h)

  • 该方法返回指定接口的代理类的实例, 该接口将方法的调用分派给执行的调用处理程序
  • 该方法有三个参数:
    1. ClassLoader: 类加载器
    2. Class [] interfaces : 被代理类实现的所有接口
      • 这里我们可以看到该参数被定义为了要一个数组, 因为一个类可以实现多个接口
    3. 实现接口InvocationHandler(我们可以选择匿名内部类的方式, 或者直接创建一个类实现该接口, 然后创建该接口实现类的对象)
      • 我们要重写一个invoke()方法
        • invoke : 调用
      • 这个接口是调用处理器, 每个proxy接口代理对象都有一个实现InvocationHandler接口的实现类Handler, 这个实现类中invoke方法就是proxy代理对象的实际调用处理器, 在这个invoke方法体中有被代理对象的方法逻辑实现和扩展

代码实现:

1.创建接口
package com.ffyc.spring.dao;

public interface UserDao {
    public int add(int a, int b);
    public String update(String id);
}
2.创建接口实现类
package com.ffyc.spring.dao;

public class UserDaoImpl implements UserDao{
    @Override
    public int add(int a,int b){
        return a + b;
    }

    @Override
    public String update(String id){
        return id;
    }
}
  • 注意: 实现类中的add()方法就是我们举例要增强的方法
3. 创建代理对象的类
  • 注意: 代理对象是底层使用反射创建的
package com.ffyc.spring.dao;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

public class UserDaoProxy implements InvocationHandler {
    //创建的是哪个类的代理对象, 我们就将这个类的实例传递过来, 这里我们通过有参构造传递

    private Object obj;

    public UserDaoProxy(Object obj) {
        this.obj = obj;
    }

    //增强的逻辑
    @Override
    /*
    proxy是代理对象, method是被代理的方法, args是被代理方法的参数
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        //方法之前
        System.out.println("方法之前执行"+method.getName()+"传递的参数"+ Arrays.toString(args));

        //被代理的方法执行
        Object res = method.invoke(obj,args);

        //方法之后
        System.out.println("方法之后执行"+obj);
        return res;
    }
}
  • 注意: UserDaoProxy类实现了InvocationHandler接口, 我们在使用Proxy类调用newInstance()方法的时候就需要传入一个InvocationHandler接口实现类的对象, 我们就创建一个UserDaoProxy类的对象, 然后将这个对象放到newInstance方法的第三个参数, 在创建UserDaoProxy类的对象的时候我们要调用有参构造, 要通过有参构造将我们的UserDaoImpl类的对象传入, 我们要将UserDaoImple类的对象传入用于底层调用Method类的invoke()方法使用
  • UserDaoProxy类中的invoke方法的三个参数:
    1. proxy : 代理对象
      • 该代理对象是底层通过反射实现的, 是封装好的, 注意: 这个方法我们自己不用调用
    2. method : 被代理方法对应的Method对象
  1. args : 被代理方法的形参
  • 使用method调用invoke方法是执行这个方法, 但是需要传递两个参数:

    1. 这个方法所在类的对象
    2. 这个方法的形参列表
    • 其实我们也能猜到是这两个参数, 因为我们要调用某个方法肯定就是要知道该方法是由哪个对象调用的, 以及这个方法的形参列表, 要调用该方法就要给方法传递形参值
4. 使用Proxy类创建接口代理对象
package com.ffyc.spring.dao;

import java.lang.reflect.Proxy;

public class JDKProxy {
    public static void main(String[] args) {
        Class [] interfaces = {UserDao.class};
        UserDaoImpl userDao = new UserDaoImpl();
        UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
        int res = dao.add(1,2);
        System.out.println(res);
    }
}
  • 这里我们注意: 我们调用Proxy.newProxyInstance()方法创建的代理对象最终也会是实现UserDao接口的(代理对象是由JVM帮我们创建的)

摘录:

ClassLoader :

被代理类的类加载器,方法内部会调用这个类加载器来获取继承Proxy类的子类字节码文件对象Class,加载的同时该子类也实现所有指定的接口。

Class<?>[] interfaces:

被代理类 的所有实现接口的Class对象,在方法内部会克隆一份加载进Proxy字节码对象中。

表示实现Proxy类实现所有指定接口。

InvocationHandler接口:(调用处理器)
1. InvocationHandler is the interface implemented by the invocation handler of a proxy instance. 
2. 调用处理器是一个通过 代理对象的调用处理器(Handler实现类中的invoke) 来实现的接口
 
3. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
4. 每一个代理对象都有相关联的调用处理器。 当一个方法伴随所属代理对象被调用,这个方法调用就会被编码转移为调用处理器中的相应扩展方法调用。

总的来讲,每一个proxy代理对象都有一个实现InvocationHandler接口的实现类Handler,这个实现类中的invoke方法就是proxy代理对象的实际调用处理器,在这个invoke方法体中,有所有 被代理对象 的方法逻辑实现和扩展。

每当代理对象proxy被反射机制用于调用其方法时,这个方法调用就自动转移为Handler类里invoke方法体中的对应扩展方法调用。

InvocationHandler这个接口的唯一一个方法 invoke 方法:

Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy:代理对象,只是反射机制调用方法的需要
method: proxy被反射机制用于调用的方法对象
args:调用方法的参数列表
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值