静态代理和动态代理以及JDK动态代理的Proxy和InvocationHandler(容易理解)

目录

  1. 什么是代理?
  2. 什么是静态代理?
  3. 什么是动态代理?
  4. 什么是Proxy?
  5. 什么是InvocationHandler?

1. 什么是代理

生活中的代理:租客因为一些原因(找不到房源、怕被坑等)需要中介来帮助他来租房。在租房的过程中,可以借助中介来干一些其他的事情(砍价,拟合同…)
程序中的代理:当前类因为一些原因(无法修改导入包的代码等)需要 代理类 来帮助自己执行方法。在执行的过程中,可以让 代理类 来干一些其他事情(输入,修改值…)

2. 什么是静态代理

代理类需要自己去创建,编写代码。
不多说废话,直接上代码

/**
 * 租房接口
 */
public interface Rent {
	void rentHourse();
}
/**
 * 代理类,中介
 */
public class Mediation implement Rent {
	@Override
	public void rentHourse() {
		// 在租房之前进行砍价
		System.out.println("租房");
		// 在租房之后进行合同保管
	}
}
/**
 * 租户
 */
public class Tenant {
	public void rent() {
		// 让中介代理租房子
		new Mediation().rentHourse();
	}
}

当项目中目标类和代理类很多的时候,会有以下的问题:
(1)当目标类增加了,代理类可能也需要成倍的增加,代理类数量过多。
(2)当你的接口中功能增加了,或者修改了,会影响众多的实现类,厂家类,代理都需要修改,影响比较多。

因此,需要用到 动态代理类

3. 什么是动态代理

在程序执行过程中,使用jdk的反射机制,创建代理类对象,并动态的指定要代理目标类(静态代理中,代理目标是固定,写死的)。而不用创建代理类文件。

2. 什么是Proxy

Proxy 是代理类,一般使用 newProxyInstance() 方法来获取代理对象实例

说一下newProxyInstance()方法

/**
 * 获取代理对象实例
 * @param loader 用这个类加载器来加在对象实例
 * @param interfaces 需要代理的真实对象所实现的所有接口组成的数组,这样代理对象就可以使用接口里的各个方法了
 * @param h 该代理实例对应的 调用处理程序(对象实例)
 */
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

3. 什么是InvocationHandler

首先,来看一下JDK文档里面的定义:

public interface InvocationHandler

InvocationHandler是一个由代理实例的 调用处理程序 实现的接口
每个代理实例都有一个关联的 调用处理程序。当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的 invoke 方法。

当看到这些名词的时候是不是有点懵?反正我第一次看到的时候是看不懂这个意思的。
首先,我们来看一下这些名词是什么意思:

  • 代理实例
    代理类的实例。比如,上面的导购员是一个类,只是一个职务,而职务是导购员的这个人,就是这个类的实例,即代理实例
  • 调用处理程序
    这是一个类,会关联着一个代理实例,需要实现InvocationHandler这个接口。作用就是,一使用代理对象实例的方法时,就会先转到它的invoke方法

下面来举一个例子,看看如何使用:

/**
 * 工作接口
 */
public interface Work {
    void work(String workName);
}
/**
 * 人
 */
public class People implements Work{
    @Override
    public void work(String workName) {
        System.out.println("workName=" + workName);
    }
}
/**
 * 调用处理程序
 */
public class WorkHandler implements InvocationHandler {
	// 要代理的真实对象
    People people;

	// 传入一个真实类的实例,给该类真实对象复制
    public void setPeople(People people) {
        this.people = people;
    }

    /**
     * @param proxy 代理对象
     * @param method 我们需要调用的那个方法所对应的对象
     * @param args 调用对象时的参数
     * @return 需要代理的真实对象(也可以返回其他Object对象,比如 形参proxy)
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("在生成真实对象前做某些事");
        Object invoke = method.invoke(people, args);
        System.out.println("在生成真实对象后做某些事");
        System.out.println(method.getName());
        return invoke;
    }
/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {
        People people = new People();
        WorkHandler workHandler = new WorkHandler();
        // 设置需要代理的真正对象实例
        workHandler.setPeople(people);
        /**
         * 通过Proxy类的newProxyInstance方法创建代理对象
         * 第一个参数:people.getClass().getClassLoader(),使用handler对象的classloader对象来加载我们的代理对象
         * 第二个参数:people.getClass().getInterfaces(),这里为代理类提供的接口是真实对象实现的接口,这样代理对象就能像真实对象一样调用接口中的所有方法
         * 第三个参数:handler,我们将代理对象关联到上面的InvocationHandler对象上
         */
        Work proxy = (Work) Proxy.newProxyInstance(people.getClass().getClassLoader(),
                people.getClass().getInterfaces(), workHandler);
        proxy.work("唱跳rap篮球");
        //System.out.println(proxy);
    }
}

总结

  • Proxy 是一个代理类,用来给真实对象创建代理实例的
  • InvocationHandler 是 代理对象实例 对应的 调用处理程序 必须实现的接口。实现类该接口后,需要重写它的invoke方法。每次代理对象实例调用方法时,都会先执行该invoke方法。可以用于横向增加需要代理的真实对象的方法的功能(AOP)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值