代理模式

Posted 阿呆很呆非常呆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代理模式相关的知识,希望对你有一定的参考价值。

代理模式,在不改变目标对象的结构、功能的前提下,对目标对象的功能进行增强。

一、静态代理

  描述:目标对象和代理对象都实现同一个接口或者同一父类。可以实现在不修改目标对象的基础上,增强目标对象的处理功能。

  缺点:固化。可能会存在大量的目标对象和代理对象。并且,如果接口变动的话,那么所有的目标对象和代理对象都必须得修改,不灵活,扩展维护性差。

  简单代码演示:

    接口类:

package com.cn.agent.staticAgent.byInterface;

public interface IUserDao {

    void save();
}

    目标类:

package com.cn.agent.staticAgent.byInterface;

/**
 * 目标对象类
 * @author cfang
 * 2018年5月25日 下午3:50:56
 */
public class UserDao implements IUserDao{

    public void save(){
        System.out.println("--- 调用目标对象方法 ---");
    }
}

    代理类:

package com.cn.agent.staticAgent.byInterface;

/**
 * 静态代理类
 * @author cfang
 * 2018年5月25日 下午3:50:44
 */
public class UserDaoProxy implements IUserDao{

    //接收并保存目标对象
    private IUserDao target;
    public UserDaoProxy(IUserDao target){
        this.target = target;
    }
    
    @Override
    public void save(){
        System.out.println("--- 代理对象类方法调用开始  ---");
        target.save();
        System.out.println("--- 代理对象类方法调用结束  ---");
    }
}

  测试main方法

package com.cn.agent.staticAgent.byInterface;

public class App {

    public static void main(String[] args) {
        //目标对象
        IUserDao target = new UserDao();
        //代理对象
        IUserDao proxy = new UserDaoProxy(target);
        
        proxy.save();
    }
}

 

二、动态代理

  描述:目标对象和静态代理相同。代理对象无需实现接口。代理对象的生成,通过jdk的java.lang.reflect.Proxy中的newProxyInstance方法去产生。

  简单代码演示:

  接口类、目标类代码同静态代理中定义。

  代理类

package com.cn.agent.dynamicAgent;

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

public class ProxyFactory {

    //存放目标对象类
    private Object target;
    public ProxyFactory(Object target){
        this.target = target;
    }
    
    //生成代理对象
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(), //ClassLoader -- 
                target.getClass().getInterfaces(),  //Class<?>[] interfaces -- 
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("代理类方法执行开始");
                        Object result = method.invoke(target, args);
                        System.out.println("代理类方法执行结束");
                        return result;
                        
                    }
                });
    }
}

  测试main方法

package com.cn.agent.dynamicAgent;

public class App {

    public static void main(String[] args) {
        
        //目标对象类
        IUserDao target = new UserDao();
        System.out.println("原始目标对象类:" + target.getClass());
        
        //代理对象类
        IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
        System.out.println("代理对象类:" + proxy.getClass());
        
        proxy.save();
    }
}

 

三、cglib代理

  描述:静态代理和动态代理,都要求目标对象去实现一个接口。但是,有时候,目标对象只是个单独的类对象。这时候,可以利用cglib代理,在内存中虚构一个目标对象的子类对象,从而实现对目标对象的功能增强。

  简单代码演示

  目标类

package com.cn.agent.cglibAgent;

public class UserDao {

    public void save(){
        System.out.println("--- 我是目标对象类非final方法 ---");
    }
    
    public final void save2(){
        System.out.println("--- 我是目标对象类final方法 ---");
    }
    
    public String save3(){
        System.out.println("--- 我是有返回的方法 ---");
        return "hello world";
    }
    
    public String save4(String param){
        System.out.println("--- 我是带参的有返回的方法 ---");
        return param;
    }
}

  代理类

package com.cn.agent.cglibAgent;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * Enhancer - 主要的增强类
 * MethodInterceptor - 方法拦截类,继承自Callback接口
 * @author cfang
 * 2018年5月25日 下午5:26:49
 */
public class ProxyFactory implements MethodInterceptor{

    //存放目标对象类
    private Object target;
    
    public ProxyFactory(Object target){
        this.target = target;
    }
    
    //创建代理类
    public Object getProxyInstance(){
        //基本工具类 :设置回调函数、设置父类、生成代理子类
        Enhancer enhancer = new Enhancer();
        //设置父类 : 设置生成的代理对象的父类
        enhancer.setSuperclass(target.getClass());
        //设置回调 : Callback接口的实例
        enhancer.setCallback(this);
        
        //设置多组回调
//        Callback[] callbacks = new Callback[]{this,this};
//        enhancer.setCallbacks(callbacks);
        //回调选择器,根据不同返回值,调用callbacks中不同的回调。返回值和callbacks回调的下标对应
//        enhancer.setCallbackFilter(new TestFilter());
        //生成子类
        return enhancer.create();
    }

    /**
     * 拦截增强方法
     */
    @Override
    public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy proxy) throws Throwable {
        System.out.println("proxy:" + proxy);
        System.out.println("--- 代理对象增强方法开始 ---");
        
//        Object result = method.invoke(target, arg2);
        Object result = proxy.invokeSuper(arg0, arg2);
        
        System.out.println("--- 代理对象增强方法结束 ---");
        return result;
    }
    
    
}

  测试main方法

  

package com.cn.agent.cglibAgent;

public class App {

    public static void main(String[] args) {
        
        //目标对象
        UserDao target = new UserDao();
        //代理对象
        UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance();
        
        proxy.save();
        
        proxy.save2();
        
        System.out.println(proxy.save3());
        
        System.out.println(proxy.save4("Test"));
        
    }
}

 

ps:spring中,基于接口的都是利用jdk动态代理,而其他都是利用cglib的代理机制。

  水平有限,欢迎指正。

以上是关于代理模式的主要内容,如果未能解决你的问题,请参考以下文章

scrapy按顺序启动多个爬虫代码片段(python3)

用于从 cloudkit 检索单列的代码模式/片段

java代码实现设计模式之代理模式

代理模式(静态代理动态代理)代码实战(详细)

Java设计模式-代理模式之动态代理(附源代码分析)

代理模式(静态代理)