动态代理模式和责任链模式

动态代理模式和责任链模式

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

   先来谈谈什么是代理模式。假设这样一个场景,你的公司是一家软件公司,你是以为软件工程师。客户带着需求去找公司显然不会直接和你谈,而是找商务谈,此时客户认为商务就代表公司。

      客户(调用者)——>商务(代理对象)——>软件工程师(真实对象)

显然客户是通过商务区访问软件工程师的,那么商务的意义在于干什么呢?

   商务可以进行谈判,比如项目启动前的商务谈判,软件的价格、交付、进度的时间节点等,或者项目完成后的商务追讨收账款。商务也有可能在开发软件之前谈判失败,此时商务会根据公司的规矩区结束和客户的合作关系,这些都不用软件工程师来处理。

   因此,代理的作用就是,在真实对象访问之前或者之后加入相应的逻辑,或者根据其他规则控制是否使用真是对象,显然在中国例子里商务控制了客户对软件工程师的访问。

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

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

1. 代理对象和真实对象建立代理关系

2. 实现代理对象的代理逻辑方法

 

Java中又多种动态代理技术,比如JDK\CGLIB\Javassist\ASM,其中最常用的动态代理技术有两种:

一种是JDK动态代理,这是JDK自带的功能。

另一种是CGLIB,这是第三方提供的一个技术。

Spring常用JDKCGLIB,而MyBatis还是用了javassist

 

 

JDK动态代理

JDK动态代理是java.lang.reflect.*包提供的方式,它必须借助一个接口才能产生代理对象,所以先定义接口。

//定义接口

public interface HelloWorld {

    public void sayHelloWorld();

}

//实现接口

public class HelloWorldImpl implements HelloWorld{

 

    @Override

    public void sayHelloWorld() {

        // TODO Auto-generated method stub

        System.out.println("Hello World");

    }

 

}

 

先要建立起代理对象和真实服务对象的关系,然后实现代理逻辑。

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

 

 

 

importjava.lang.reflect.InvocationHandler;

importjava.lang.reflect.Method;

importjava.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

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        /sTODO Autohmethod stub

        System.out.println("进入代理逻辑方法");

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

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

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

        return obj;

    }

 

}

1.     建立代理对象和真实对象的关系。

这里是用bind方法区完成的。

其中newProxyInstance方法包含了三个参数。

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

第二个是把生成的动态代理对象下挂在哪些接口的下面,这个写法就是放在target是实现的接口下。HelloWorldImpl对象的接口显然就是HelloWorld,代理对象可以这么申明:

HelloWorld proxy = xxxx;

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

 

2.     实现代理逻辑方法。

Invoke方法可以实现代理逻辑

三个参数含义:

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

Method,当前调度的方法

Args,调度方法的参数

 

Proxy相当于商务对象,target相当于软件工程师对象,bind方法就是建立商务和软件工程师代理关系的方法。而invoke就是商务逻辑,它控制软件工程的访问。

 

测试

public class TestJdkProxy {

    public static void main(String[] args) {

        JdkProxyExample jdk = new JdkProxyExample();

        //绑定关系,因为挂在接口hellword下,所以声明代理对象helloworld proxy

        HelloWorld proxy = (HelloWorld) jdk.bind(new HelloWorldImpl());

        proxy.sayHelloWorld();;

    }

 

}

结果

猜你喜欢

转载自blog.csdn.net/iXinRu/article/details/79834518