代理模式

作者: 降龙_伏虎 | 来源:发表于2019-06-19 10:57 被阅读0次

1.概念

代理模式(Proxy Pattern) 是指为其它对象提供一种代理,以控制这个对象的访问,
代理对象在客户端和目标对象之间起到中介作用,
属于结构型设计模式

2.静态代理

"非专业"中介,只能为特定对象进行代理,如父母代理儿子找对象;
代码中指为某个特定的对象的特定方法进行代理,
不具有通用性,以及动态切换的能力
/**
 * Description:儿子类(被代理对象)
 *
 * @date 2019-05-08 19:39
 */

public class Son{

    /**
     * Description:找对象要求
     * @Date  2019-05-08 19:40
     * @Param []
     * @return java.lang.String
    **/

    public String findLove(){
        return  "租房要求:女的";
    }
}

/**
 * Description:父亲类(代理人)
 *
 * @date 2019-05-08 19:41
 */

public class Father {

    private  Son son;

    public Father(Son son) {
        this.son = son;
    }

    public String helpFindLove(){
        System.out.println("父亲帮儿子找对象开始");//此处可进行特殊处理
        String s =  son.findLove();
        System.out.println("儿子找对象要求:"+s);
        System.out.println("父亲帮儿子找对象结束");//此处可进行特殊处理
        return s;
    }
}

/**
 * Description:静态代理测试
 *
 * @date 2019-05-08 19:47
 */

public class Test {
    public static void main(String[] args) {
        Father father = new Father(new Son());
        father.helpFindLove();
    }
}

3.动态代理

"专业"中介,能为所有对象进行代理,如婚介所;
具有通用性,以及动态切换的能力

3.1 JDK 动态代理

/**
 * Description:人接口
 *
 * @date 2019-05-09 19:33
 */

public interface Person {

    void findLove();
}



/**
 * Description:女孩类
 *
 * @date 2019-05-09 19:32
 */

public class Girl implements Person{

    @Override
    public void findLove(){
        System.out.println("要求:是男的");
    }
}

/**
 * Description:媒婆
 *
 * @date 2019-05-09 19:36
 */

public class MeiPo implements InvocationHandler {

    //被代理对象
    private Person target;

    //获取JDK代理
    public Object getInstance(Person person){
        this.target = person;
        Class<?> clazz = target.getClass();
        //根据被代理对象信息获取代理对象(被代理对象被代理对象"包裹")
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        befor();
        Object obj =  method.invoke(this.target,args);
        after();
        return obj;
    }

    private void befor(){
        System.out.println("代理前置操作...");

    }

    private void after(){
        System.out.println("代理后置操作...");
    }
}

/**
 * Description:JDKd动态代理测试类
 *
 * @date 2019-05-09 19:44
 */

public class Test {

    public static void main(String[] args) {

        try {
            Person obj = (Person)new MeiPo().getInstance(new Girl());
            obj.findLove();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

原理

将被代理对象做相关特殊包装后 通过"动态生成字节码"生成一个新的"被包装"的类
/**
 * 通道JDK代理生成的类
 * ① 新的类继承Proxy
 * ② 新的类实现Person接口
 *
 *
**/

public final class $Proxy0 extends Proxy implements Person {
....
    //被代理对象的方法
    public final void findLove() throws  {
        try {
            //执行媒婆对象的invoke方法&将当前对象传入媒婆
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
....

}

手工模拟JDK动态代理

/**
 * Description:人接口
 *
 * @date 2019-05-09 19:33
 */

public interface Person {

    void findLove();
}

/**
 * Description:女孩类
 *
 * @date 2019-05-09 19:32
 */

public class Girl implements Person{

    @Override
    public void findLove(){
        System.out.println("要求:是男的");
    }
}

/**
 * Description:代理
 *
 * @date 2019-05-13 19:53
 */

public class SkyMeiPo implements SkyInvocationHandler{

    //被代理对象
    private Person target;

    //获取JDK代理
    public Object getInstance(Person person){
        this.target = person;
        Class<?> clazz = target.getClass();
        //根据被代理对象信息获取代理对象(被代理对象被代理对象"包裹")
        return SkyProxy.newProxyInstance(new SkyClassLoader(),clazz.getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        befor();
        Object obj =  method.invoke(this.target,args);
        after();
        return obj;
    }

    private void befor(){
        System.out.println("代理前置操作...");

    }

    private void after(){
        System.out.println("代理后置操作...");
    }
}

/**
 * Description:
 *
 * @date 2019-05-13 19:50
 */

public class SkyProxy {

    private static final String LN = "\r\n";

    @CallerSensitive
    public static Object newProxyInstance(SkyClassLoader loader,
                                          Class<?>[] interfaces,
                                          SkyInvocationHandler h)
            throws IllegalArgumentException {
        
        try {
            //1.动态生成代码
            String src = generateSrc(interfaces);
            System.out.println(src);
            //2.java文件输出到磁盘
            String filePath = SkyProxy.class.getResource("").getPath();
            File f = new File(filePath+"$Proxy0.java");
            FileWriter fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
            fw.close();
            //编译代码
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//获取系统编译器
            StandardJavaFileManager manager = compiler.getStandardFileManager(null,null,null);
            Iterable iterable = manager.getJavaFileObjects(f);
            JavaCompiler.CompilationTask task = compiler.getTask(null,manager,null,null,null,iterable);
            task.call();
            manager.close();

            Class proxyClass = loader.findClass("$Proxy0");
            Constructor c = proxyClass.getConstructor(SkyInvocationHandler.class);

            return c.newInstance(h);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }


    private static String generateSrc(Class<?>[] interfaces) {
        /*用代码写代码*/
        StringBuffer sb = new StringBuffer();
        //引包
        sb.append("package com.sky.designpattern.proxy.dynamicproxy.custom;").append(LN);
        sb.append("import com.sky.designpattern.proxy.dynamicproxy.jdk.Person;").append(LN);
        sb.append("import java.lang.reflect.Method;").append(LN);
        //类头
        sb.append("public class $Proxy0 implements ").append(interfaces[0].getName()).append("{").append(LN);
        //声明变量
        sb.append("SkyInvocationHandler h;").append(LN);
        //构造方法
        sb.append("public $Proxy0(SkyInvocationHandler h){").append(LN);
        sb.append("this.h=h;").append(LN);
        sb.append("}").append(LN);

        //反射生成方法
        for(Method m:interfaces[0].getMethods()){
            sb.append("public ").append(m.getReturnType().getName()).append(" ").append(m.getName()).append("(){").append(LN);
                sb.append("try{").append(LN);
                    sb.append("Method m = ").append(interfaces[0].getName()).append(".class.getMethod(\""+m.getName()+"\",new Class[]{});").append(LN);
                    sb.append("this.h.invoke(this,m,null);").append(LN);
                sb.append("}catch(Throwable e){").append(LN);
                    sb.append("e.printStackTrace();").append(LN);
                sb.append("}").append(LN);

            sb.append("}").append(LN);
        }

        sb.append("}");

        return sb.toString();
    }
}

public interface SkyInvocationHandler {

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

public class SkyClassLoader extends ClassLoader{

    private File classPathFile;


    public SkyClassLoader() {
        String classPath = SkyClassLoader.class.getResource("").getPath();
        this.classPathFile = new File(classPath);

    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String className = SkyClassLoader.class.getPackage().getName()+"."+name;
        if(classPathFile !=null){
            File classFile = new File(classPathFile,name.replaceAll("\\.","/")+".class");
            if(classFile.exists()){
                FileInputStream in =null;
                ByteArrayOutputStream out = null;
                try{
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte [] buff = new byte[1024];
                    int len;
                    while ((len = in.read(buff)) != -1){
                        out.write(buff,0,len);
                    }
                    return defineClass(className,out.toByteArray(),0,out.size());
                }catch (Exception e){

                }

            }
        }
        return null;
    }
}


3.2cglib动态代理

3.2.1与JDK的区别

1.JDK动态代理是通过反射实现,而cglib是通过生成被代理类的子类
    来实现
2.cglib因为没用到反射效率更高
3.不可代理 final类
4.被代类不需要实现统一接口

3.2.2代码实现

/**
 * Description:被代理类
 *
 * @date 2019-05-22 20:11
 */

public class Persion {


    public void  findLove(){
        System.out.println("肤白貌美大长腿");
    }

}

/**
 * Description:代理类
 *
 * @date 2019-05-22 20:01
 */

public class MeiPo implements MethodInterceptor {


    public Object getInstance(Class<?> clazz) throws Exception{
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();

    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object object = methodProxy.invokeSuper(o,objects);
        after();
        return object;
    }

    private void before(){
        System.out.println("before");

    }
    private void after(){
        System.out.println("after");

    }
}
/**
 * Description:测试类
 *
 * @date 2019-05-22 20:01
 */
public class Test {


    public static void main(String[] args) {

            try {
                Persion persion = (Persion) new MeiPo().getInstance(Persion.class);
                persion.findLove();
            } catch (Exception e) {
                e.printStackTrace();
            }

    }

}

相关文章

  • 设计模式

    单例模式 模板方法模式 工厂模式 代理模式 静态代理 JDK动态代理

  • 设计模式

    单例模式 代理模式 静态代理 jdk动态代理 cglib动态代理 工厂模式 适配器模式 建造者模式 观察者模式

  • kube-proxy的3种模式

    userspace代理模式 iptables代理模式 IPVS代理模式 https://kubernetes.io...

  • 第4章 结构型模式-代理模式

    一、代理模式简介 二、代理模式3个角色 三、代理模式的优点 四、代理模式的实例(游戏代练)

  • 理解代理模式

    原创博客地址 简介 代理模式,也叫做委托模式,分为:静态代理动态代理 代理模式也是平时比较常用的设计模式之一,代理...

  • 结构型 代理模式(文末有项目连接)

    1:什么是代理模式 2:没用代理模式时的实例 3:使用代理模式将其解耦(静态代理) 3:使用代理模式将其解耦(动态...

  • 设计模式-动态代理模式

    之前介绍了代理模式,大家也都了解了代理模式,不过之前介绍的代理模式是静态代理,静态代理什么意思?静态代理指的是代理...

  • 代理模式

    一、什么是代理模式 代理模式(Proxy pattern):代理模式又叫委托模式,是为某个对象提供一个代理对象,并...

  • 设计模式之代理模式(Proxy模式)

    代理模式的引入 代理模式的实例程序 代理模式的分析 代理模式的引入 Proxy是代理人的意思,指的是代替别人进行工...

  • Java设计模式之代理模式

    Java设计模式之代理模式 代理模式 静态代理 动态代理 为什么需要代理 通过代理,我们能够不用知道委托人是谁,而...

网友评论

    本文标题:代理模式

    本文链接:https://www.haomeiwen.com/subject/hdehqctx.html