代理设计原理剖析

一、代理的概念

1. 设计模式:前人总结的一套解决特定问题的代码套路

2. 代理设计模式优点:

2.1 保护真实对象
2.2 让真实对象职责更明确.
2.3 便于扩展功能

3. 代理设计模式的组成部件:三个

3.1 真实对象.(老总)
3.2 代理对象(秘书)
3.3 抽象对象(抽象功能):老总需要总的事情(为接口)

二、静态代理

1. 由代理对象代理所有真实对象的功能.

1.1 程序员字节编写代理类
1.2 每个代理的功能需要单独编写

2. 静态代理设计模式的缺点:

2.1 当代理功能比较多时,代理类中方法需要写很多.

3、静态代理例子:

A、抽象功能接口
 * description :抽象功能接口,里面有两个方法,由程序员自主定义
 */
public interface Function {
    public void eating();
    public void working();
}
B、真实对象,实现功能接口,重写方法(也就是被代理对象,例子中的老总,老总具体干两件事:吃饭,工作)程序员自主定义
* description :真实对象
 */
public class Boss implements Function {
    @Override
    public void eating() {
        System.out.println("吃饭!");
    }

    @Override
    public void working() {
        System.out.println("谈合作!");
    }
}
C、代理对象,实现功能接口。(例子中的小秘书,找老总前必须先通过秘书,小秘书代理老总处理一些事情)程序员自主定义
* description :代理类
 */
public class MiShu implements Function {
private Boss boss;//被代理对象
    public MiShu(Boss boss) {
    this.boss=boss;
    }

    
    @Override
    public void eating() {
        System.out.println("秘书约时间!");
        boss.eating();
        System.out.println("秘书善后!");
    }

    @Override
    public void working() {
        System.out.println("秘书约时间!");
        boss.working();
        System.out.println("秘书善后!");
    }
}
D、测试
public class Test {
    public static void main(String[] args) {
        MiShu mishu = new MiShu(new Boss());
        mishu.eating();
        mishu.working();
    }
}
E、解释

通过上面的例子可以发现,静态代理需要:
1)接口
2)真实对象实现接口
3)代理对象,去代理真实对象
和老总吃饭、谈合作必须先和秘书约时间,吃完饭,谈完合作,由秘书善后。老总功能明确,职能分离。
缺点:
接口中有多少个方法,代理对象就必须对每个方法都有进行相同的处理。若有成百上千个方法,则代理类很臃肿。

三、JDK动态代理

1、为了解决静态代理的缺点(频繁编写代理的方法),JDK提供了动态代理的方式,即不需要对接口中的每一个方法进行处理。JDK动态代理是基于“反射原理”。

2、先看实例

JDK动态代理四个步骤:

1)创建接口,定义真实对象需要完成的功能
2)创建真实对象,实现接口(1、2步和静态代理相同)
3)创建InvocationHandler的实现类(我把它叫为处理器),在invoke方法中进行代理对象对被代理对象的功能的增强(改变、扩展都行)
4)使用Proxy的静态方法 Proxy.newProxyInstance,创建代理对象,被强转为接口对象,通过接口对象调用接口中的功能就能实现代理。

 * description :抽象功能类
 */
public interface Function {

    public void eating();

    public void working();

}
* description :真实对象
 */
public class Boss implements Function {
    @Override
    public void eating() {
        System.out.println("吃饭!");
    }

    @Override
    public void working() {
        System.out.println("工作!");
    }
}
* description :处理器,实现代理功能
 */
public class MyHandler implements InvocationHandler {
    private Boss boss = new Boss();

    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        System.out.println("秘书善后!");
        Object result = method.invoke(boss, objects);
        System.out.println("秘书善后");
        return result;
    }
}
* description :测试类
 */
public class Test {
    public static void main(String[] args) {
        MyHandler myHandler = new MyHandler();
        //第一个参数:反射使用的类加载器
        //第二个参数:Proxy需要实现的接口
        //第三个参数:通过接口对象调用方法时,需要调用哪个类的invoke方法
       Function f=(Function) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{Function.class}, myHandler);
       f.eating();
       f.working();
    }
}

运行结果:

	预约时间!
	吃饭!
	秘书善后!
	预约时间!
	工作!
	秘书善后!

3、运行的实质剖析

1、在 test中 new 一个MyHandler 的对象。MyHandler 实现了接口 InvocationHandler,重写 invoke 方法

invoke方法参数:

Object o:代理对象,由JDK自动传入,不需要程序员管理。
Method method:真实对象需要执行的功能方法对象,通过反射获取。也是有JDK自动传入,不需要程序员管理
Object[] objects:真实对象需要执行的功能方法所需要的参数,JDk自动传入
method是方法对象,由反射获取,这里的真实对象是 private Boss boss = new Boss();,通过反射获取到它的对应的方法对象。
通过 Object result = method.invoke(boss, objects);执行真实对象中的功能,并将执行结果返回
public class MyHandler implements InvocationHandler {
    private Boss boss = new Boss();

    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        System.out.println("预约时间!");
        Object result = method.invoke(boss, objects);
        System.out.println("秘书善后!");
        return result;
    }
}

2、问题的核心在:
Function f=(Function) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{Function.class}, myHandler);

1) newProxyInstance 是用来创建一个代理类对象

2)参数
Test.class.getClassLoader()
类加载器(需要知道类加载器的概念和作用,以及类加载的过程:简单的说就是一个java代码文件,编译后生成对应的class文件(也就是字节码文件),类加载器就是将这个class文件加载到 jvm 内存,加载完成后会生成这个类的类对象(Class类型的对象),通过这个类对象我们可以获取到这个类的结果),通常是:AppClassLoader

new Class[]{Function.class}:
真实对象实现的接口的类对象,真实对象可能实现多个接口,因此需要CLass[]存放

myHandler:
处理器:也就 MyHandler,将处理器的处理以对象的形式传入。

3)newProxyInstance 获取到上面三个参数后,会动态创建对应的代理类,并返回这个代理类的实例。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值