Java设计模式之动态代理

写在前面,最近在学习java,动态代理这部分看的头疼,先将书上的例子自己实现了下,好在例子还比较能理解,先记录一下,以便加深印象,后面需要用到的时候,再去深入理解。

动态代理的意义在于生成一个占位(又称代理对象),来代理真实的对象,从而控制真实对象的访问。

代理模式,假设你有一家公司,你的公司是一家软件公司,你是一位软件工程师。客户带着需求去找公司肯定不会直接和你谈,而是去找商务谈,此时客户会认为商务就代表公司。

此时商务就是一个代理对象,客户是通过商务去访问软件工程师的。商务的可以进行谈判,比如项目启动前的商务谈判,软件的价格、交付、进度的事件节点等,或者项目完成后商务追讨应收帐款等。商务也有可能在软件开发前谈判失败,此时就会结束和客户的合作,这些都不用软件工程师来处理。

因此,代理的作用就是,在访问真实对象(这里软件工程师就是真实对象)或者之后,加入对应的逻辑,或者根据规则决定是否访问真实对象。

通过上面的论述可以得出,商务和软件工程师就是代理与被代理的关系,客户是经过商务去访问软件工程师的。此时客户就是程序中的调用者,商务就是代理对象,软件工程师就是真实对象。

我们需要在调用者调用对象之前产生一个代理对象,而这个代理对象需要和真实对象建立代理关系,所代理必须分为两个不住:

  • 代理对象和真实对象建立代理关系
  • 实现代理对象的代理逻辑方法

下面来完成一个利用JDK来实现动态代理的例子,JDK的动态代理是java.lang.feflect.*包提供的方式,他有一个局限性在于,必须借助一个接口才能产生代理对象,因此我们首先需要定义一个接口。

public interface HelloWorld {
    public void sayHelloWorld(String name);
}

然后提供一个类来实现这个接口

public class HelloWorldImp1 implements HelloWorld {
    @Override
    public void sayHelloWorld(String name)
    {
        System.out.println("helloworld "+name);
    }
}

接下来就是动态代理的实现了,根据上面的分析,首先要建立代理和真实对象之间的关系,然后实现在理逻辑。

在JDK动态代理中,要实现代理逻辑类必须去实现import java.lang.reflect.InvocationHandler接口,它里面定义了一个invoke方法,并提供接口数组用于下挂代理对象。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//代理对象
public class JdkProxyExample implements InvocationHandler {

    //真实对象
    private Object target=null;
    /**
     * 建立代理对象和真实对象的代理管理,并返回代理对象
     * @param target 真实对象
     * @return 代理对象
     */
    public Object bind(Object target){
        this.target=target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }
    @Override

    /**
     * 代理方法逻辑
     * @param proxy 代理对象
     * @param method 当前调度方法
     * @param args 当前方法参数
     *
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("进入代理逻辑方法");
        System.out.println("在调度真实对象之前的服务");
        Object obj=method.invoke(target,args);   //想当于调用sayHelloWorld方法

        System.out.println("在调度真实对象之后的服务");
        return obj;

    }

}

第一步,建立代理对象和真实对象的关系。这里是使用了bind()方法去完成的,方法里面首先用类的属性target保存了真实对象,然后通过如下的代码建立并生成代理对象。

Proxy.newProxyInstance(

target.getClass().getClassLoader(),

target.getClass().getInterfaces(),

this);

其中newProxyInstance方法包含三个参数

第一个是类加载器,采用了target本身的类加载器。

第二个是把生成的动态代理对象挂在那些接口下面,这个写法就是放在target实现的接口下,HelloWorldImp1对象的接口显然是HelloWorld,代理对象可以这样声明:HelloWorld proxy

第三个是定了实现方法逻辑的代理类,this,表示当前对象,它必须实现InvocationHandler接口的invoke方法,它就是代理逻辑方法的现实方法。

第二步,实现代理逻辑方法。Invoke方法可以实现代理逻辑,invoke方法的三个参数的含义如下:

proxy,代理对象,就是bind方法生成的对象。

method,当前调度的方法

args,调度方法的参数,

当我们使用了代理对象的调度方法后,他就会进入到invoke方法里面

Object obj=method.invoke(target,args);  

这行代码相当于调度真实对象的方法,只是通过反射实现。

类比前面的例子,proxy相当于商务对象,target相当于软件工程师对象,bind方法是建立商务和软件工程代理关系的方法,而invole就是商务逻辑,他将控制软件工程师的访问。

下面将对上面的动态代理进行测试

public static void main(String[] args)
    {
        JdkProxyExample jdk=new JdkProxyExample();
        HelloWorld proxy=(HelloWorld)jdk.bind(new HelloWorldImp1());

        //此时 HelloWorld对象已经是一个代理对象,他会进入代理的逻辑方法invoke;
//然后invoke里面的method.invoke方法会进入到被代理对象target的sayHelloWorld方法
        proxy.sayHelloWorld("java");
    }

首先通过bind方法绑定了代理关系,然后再代理对象调度sayhelloworld方法时,进入了代理的逻辑,测试结果如下。

此时在调度输出helloworld java之前或者之后,都可以加入相关的逻辑,甚至可以设置相关条件,如条件不满足,则不调用sayhelloworld方法。

对比之前的例子,商务在访问软件工程师之前和之后,都可以进行一些列的操作,甚至可以在谈判失败后,不去访问软件工程师。

对于代理的理解,还有待于后面使用了之后,才能更加深入,在Spring和MyBiatis中,动态代理有着重要的应用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值