动态代理的理解

1.代理模式概述

为什么要有“代理”? 生活中就有很多例子,例如委托业务等等,代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,这才是“代理”存在的原因。例如,我现在需要出国,但是我不愿意自己去办签证、预定机票和酒店(觉得麻烦 ,那么就可以找旅行社去帮我办,这时候旅行社就是代理,而我自己就是被代理了。

代理模式的定义ProxyPattern(即:代理模式),23种常用的面向对象软件的设计模式之一为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

2.静态代理

以下我们借用JinLian和XiMen的例子来介绍一下静态代理

2.1不使用代理模式时

JinLian类的内部有一个happy方法,此时如果我们的XiMen类如果想要使用这个方法,正常情况下直接创建一个JinLian类调用happy方法即可

public class JinLian{
    public void happy() {
        System.out.println("金莲happy...");
    }
}
public class XiMen {
    public static void main(String[] args) {
        JinLian jinLian =new JinLian();
        jinLian.happy();
    }
}
2.2使用静态代理

如果我们使用静态代理模式的话,XiMen类如果想要调用happy方法,那么它便不会直接去找JinLian类,而是通过一个代理对象WangPo间接找到JinLian类。这样做的好处是,我们可以通过WangPo这个代理,在happy方法中添加一些想要的功能,例如:

public class WangPo {
    JinLian jinLian ;
    public WangPo(JinLian jinLian) {
    this.jinLian = jinLian;
}
    public void happy(){
        openHouse();
        jinLian.happy();
        clear();
    }
    public void clear(){
        System.out.println("打扫战场...");
    }
    public void openHouse(){
        System.out.println("以做衣服的名义把2人约到房间...");
    }
}//WangPo

public class XiMen {
    public static void main(String[] args) {
    	JinLian jinLian =new JinLian();
        WangPo wangPo =new WangPo(jinLian);
        wangPo.happy();
    }
}//XiMen

public class JinLian {
    public void happy() {
        System.out.println("金莲happy...");
    }
}//JinLian

这样,XiMen类想要调用happy方法,并且想要使用新增的功能时,只需要调用WangPo的happy方法即可。

2.3静态代理改进

现在,虽然实现了代理模式,但是目前的代理对象和委托对象都已经固定了,这样做局限性很大,我们的XiMen类如果想要调用其它委托者的Happy方法,就只能找其它的代理对象,此时我们对代码再次改进一下,新加一个FindHappy接口,委托者对象只需要实现FinHappy接口,便可以实现一个代理对象代理多个委托对象。如果,XiMen现在想要通过WangPo使用JinLian和YanPoXi的happy方法。我们可以做出如下改写

public interface FindHappy {// 抽象角色
    void happy();
}

public class JinLian implements FindHappy {//委托者1
    @Override
    public void happy() {
        System.out.println("金莲happy...");
    }
}//JinLian

public class YanPoXi implements FindHappy {//委托者2
    @Override
    public void happy() {
        System.out.println("阎婆惜happy...");
    }
}//YanPoXi

public class WangPo implements FindHappy {//代理者

    FindHappy findHappy;

    public WangPo(FindHappy findHappy) {
        this.findHappy = findHappy;
    }

    public void openHouse(){
        System.out.println("以做衣服的名义把2人约到房间...");
    }

    @Override
    public void happy() {
        openHouse();
        // 让委托者happy()  
        findHappy.happy();
        clear();
    }

    public void clear(){
        System.out.println("打扫战场...");
    }
}
public class XiMen {
    public static void main(String[] args) {  
        JinLian jinLian = new JinLian();
        YanPoXi yanPoXi = new YanPoXi();
        WangPo wangPo = new WangPo(yanPoXi);
        WangPo wangPo1 =new WangPo(jinLian);
        wangPo.happy();
        wangPo1.happy();
    }
}

如此一来我们便可以通过一个代理对象代理所有重写了happy方法的对象
这便是静态代理模式

3.动态代理

动态代理与静态代理的区别是,动态代理的代理对象是在使用者调用委托者的方法时才创建的,动态代理它可以直接给某一个目标(被代理 对象)对象(实现了某个或者某些接口)生成一个代理对象,也就是当XiMen类想要使用happy方法时,代理对象才会生成,并且不需要代理类存在

3.1动态代理原理

动态代理与代理模式原理是一样的,只是它没有具体的代理类,直接通过反射生成了一个代理对象。简而言之:动态代理就是直接通过反射生成一个代理对象,代理类是不需要存在的

3.2动态代理的获取及使用

jdk提供一个Proxy类可以直接给实现接口类的对象直接生成代理对象
Proxy的API介绍
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)生成一个代理对象,这个方法的返回值类型是一个Object类型,但是在此方法的第三个参数的匿名内部类中我们重写了委托者的方法,而委托者又必定实现了FindHappy接口,因此此处我们可以使用向下强转,并用一个Findhappy接口的对象进行接收
参数1:ClassLoader loader 被代理对象的类加载器, 一般使用被代理对象的类加载器
参数2:Class<?>[] interfaces 被代理对象的要实现的接口 一般使用的被代理对象实现的接口
参数3:InvocationHandler h (接口)(使用匿名内部类直接实现)执行处理类返回值: 代理对象
InvocationHandler中的invoke(Object proxy, Method method, Object[] args)方法:调用代理类的任何方法,此方法都会执行,因此当一个委托对象中有多个方法需要代理时,需要在此匿名内部类中使用反射获取方法名,判断是哪个方法在请求代理,一一实现各个方法需要增添的功能
3.1:代理对象(慎用)参数
3.2:当前执行的方法参数
3.3:当前执行的方法运行时传递过来的参数返回值:当前方法执行的返回值

public class Demo1 {
    public static void main(String[] args) {
     // 动态产生一个JinLian类的代理对象  类似生成王婆代理对象

        FindHappy proxy = (FindHappy) Proxy.newProxyInstance(JinLian.class.getClassLoader(), JinLian.class.getInterfaces(), new InvocationHandler() {
            public void openHouse(){
                System.out.println("以做衣服的名义把2人约到房间...");
            }

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 但凡是代理对象调用方法,这个invoke方法就会执行
                // 参数1proxy:代理对象(慎用),因为代理对象调用方法就会执行invoke,很容易出现递归,出现栈内存溢出
                // 参数2 method:当前代理对象调用的方法
                // 参数3:当前代理对象调用的方法,运行时传递过来的参数
                // 返回值:当前方法执行的返回值
                if(method.getName()=="happy"){
	                openHouse();
	                method.invoke(JinLian.class.newInstance());// 类似 jinLian.happy()
	                clear();
	                return null;
                }
            }

            public void clear(){
                System.out.println("打扫战场...");
            }
        });

        // 使用代理对象调用方法
        proxy.happy();
    }

以上是本人的第一篇博客,如果有错误,欢迎大家指出😁!写此篇博客的目的主要是为了如果今后在工作中,遇到使用Spring AOP及相关问题的时候,可以回顾一下自己以前的理解,温故知新

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值