资讯专栏INFORMATION COLUMN

慕课网_《模式的秘密之代理模式》学习总结

wow_worktile / 632人阅读

时间:2017年08月28日星期一
说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com
教学源码:https://github.com/zccodere/s...
学习源码:https://github.com/zccodere/s...

第一章:代理模式 1-1 概念介绍

学习本课程基础

面向对象的设计思维
了解多态的概念
了解反射机制

课程目标

代理模式基本概念及分类
了解代理模式开发中应用场景
掌握代理模式实现方式
理解JDK动态代理实现

代理模式定义

为其他对象提供一种代理以控制对这个对象的访问
代理对象起到中介作用,可去掉功能服务或增加额外的服务

常见的几种代理模式

远程代理:类似于客户端服务器这种模式,列一个为不同地理对象提供局域网代表对象
虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建
保护代理:控制对象的访问权限
智能代理:提供对目标对象额外的服务

代理模式示意图

第二章:常用代理模式 2-1 静态代理

智能引用代理

静态代理
动态代理

静态代理定义

代理和被代理对象在代理之前是确定的。他们都实现相同的接口或者继承相同的抽象类

静态代理类图

代码编写

1.编写Moveable接口

package com.myimooc.designpattern.c3proxy.car;

/**
 * @describe 可行驶的接口
 * @author zc
 * @version 1.0 2017-08-28
 */
public interface Moveable {
    
    /**
     * 行驶的方法
     */
    void move();
    
}

2.编写Car类

package com.myimooc.designpattern.c3proxy.car;

import java.util.Random;

/**
 * @describe 一辆车实现可行驶的接口
 * @author zc
 * @version 1.0 2017-08-28
 */
public class Car implements Moveable {
    
    @Override
    public void move() {
        // 记录汽车行驶的时间
//        long starttime = System.currentTimeMillis();
//        System.out.println("汽车开始行驶...");
        
        // 实现开车
        try {
            System.out.println("汽车行驶中...");
            Thread.sleep(new Random().nextInt(1000));
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
//        long endtime = System.currentTimeMillis();
//        System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
    }
    
}

3.编写Car2类

package com.myimooc.designpattern.c3proxy.car;

/**
 * @describe 继承的方式实现静态代理
 * @author zc
 * @version 1.0 2017-08-28
 */
public class Car2 extends Car {

    @Override
    public void move() {
        
        long starttime = System.currentTimeMillis();
        System.out.println("汽车开始行驶...");
        
        super.move();
        
        long endtime = System.currentTimeMillis();
        System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
        
    }
}

4.编写Car3类

package com.myimooc.designpattern.c3proxy.car;

/**
 * @describe 聚合的方式实现静态代理
 * @author zc
 * @version 1.0 2017-08-28
 */
public class Car3 implements Moveable {
    
    public Car3(Car car) {
        super();
        this.car = car;
    }

    private Car car;
    
    @Override
    public void move() {
        
        long starttime = System.currentTimeMillis();
        System.out.println("汽车开始行驶...");
        
        car.move();
        
        long endtime = System.currentTimeMillis();
        System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
        
    }

}

5.编写Client类

package com.myimooc.designpattern.c3proxy.car;


/**
 * @describe 测试类
 * @author zc
 * @version 1.0 2017-08-28
 */
public class Client {
    
    public static void main(String[] args) {
//        test1();
        test2();
        
    }
    
    // 2-2 聚合与继承 代理功能叠加测试方法
    public static void test2(){
        Car car = new Car();
        CarLogProxy clp = new CarLogProxy(car);
        CarTimeProxy ctp = new CarTimeProxy(clp);
        ctp.move();
    }
    
    // 2-1 静态代理测试方法
    public static void test1(){
//        Car car = new Car();
//        car.move();
        
        // 使用继承的方式
//        Moveable m = new Car2();
//        m.move();
        
        // 使用聚合方式
        Car car = new Car();
        Moveable m = new Car3(car);
        m.move();
    }
    
}
2-2 聚合与继承

场景分析

代理类功能叠加

1.记录日志
2.记录时间
3.权限功能

使用继承方式

使用继承方式来实现代理功能的叠加,代理类会无限的膨胀下去,所以这种方式不推荐使用。

使用聚合方式,通过代码演示

代码编写

1.复制Car3命名为CarTimeProxy

package com.myimooc.designpattern.c3proxy.car;

/**
 * @describe 汽车行驶时间的代理
 * @author zc
 * @version 1.0 2017-08-28
 */
public class CarTimeProxy implements Moveable {
    
    // 因为代理类和被代理类都是实现相同的接口,所以构造方法传递的对象也可以是Moveable对象
    public CarTimeProxy(Moveable m) {
        super();
        this.m = m;
    }

    private Moveable m;
    
    @Override
    public void move() {
        
        long starttime = System.currentTimeMillis();
        System.out.println("汽车开始行驶...");
        
        m.move();
        
        long endtime = System.currentTimeMillis();
        System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
        
    }

}

2.编写CarLogProxy类

package com.myimooc.designpattern.c3proxy.car;

/**
 * @describe 汽车日志功能的代理
 * @author zc
 * @version 1.0 2017-08-28
 */
public class CarLogProxy implements Moveable {
    
    // 因为代理类和被代理类都是实现相同的接口,所以构造方法传递的对象也可以是Moveable对象
    public CarLogProxy(Moveable m) {
        super();
        this.m = m;
    }
    private Moveable m;
    
    @Override
    public void move() {
        System.out.println("日志开始");
        m.move();
        System.out.println("日志结束");
    }
}

3.编写Client类

package com.myimooc.designpattern.c3proxy.car;


/**
 * @describe 测试类
 * @author zc
 * @version 1.0 2017-08-28
 */
public class Client {
    
    public static void main(String[] args) {
//        test1();
        test2();
        
    }
    
    // 2-2 聚合与继承 代理功能叠加测试方法
    public static void test2(){
        Car car = new Car();
        CarLogProxy clp = new CarLogProxy(car);
        CarTimeProxy ctp = new CarTimeProxy(clp);
        ctp.move();
    }
    
    // 2-1 静态代理测试方法
    public static void test1(){
//        Car car = new Car();
//        car.move();
        
        // 使用继承的方式
//        Moveable m = new Car2();
//        m.move();
        
        // 使用聚合方式
        Car car = new Car();
        Moveable m = new Car3(car);
        m.move();
    }
    
}
2-3 JDK动态代理

场景分析

有没有方法动态产生代理,实现对不同类,不同方法的代理呢

JDK动态代理类图

Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类

Interface InvocationHandler:该接口中仅定义了一个方法
    public Object invoke(Object obj,Method method,Object[] args)
    在实际使用时,第一参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。
    这个抽象方法在代理类中动态实现。
Proxy:该类即为动态代理类
    static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
    返回代理类的一个实例,返回后的代理类可以当做被代理类使用
    (可使用被代理类的在接口中声明过的方法)

所谓Dynamic Proxy是这样一种class

它是在运行时生成的class
该class需要实现一组interface
使用动态代理类时,必须实现InvocationHandler接口

动态代理实现步骤

1.创建一个实现InvocationHandler接口的类,它必须实现invoke方法
2.创建被代理的类以及接口
3.调用Proxy的静态方法,创建一个代理类
    newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
4.通过代理调用方法

代码编写

1.编写TimeHandler类

package com.myimooc.designpattern.c3proxy.jdk;

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

/**
 * @describe 对时间上的处理-使用JDK动态代理
 * @author zc
 * @version 1.0 2017-08-28
 */
public class TimeHandler implements InvocationHandler {
    
    public TimeHandler(Object target) {
        super();
        this.target = target;
    }

    private Object target;
    
    /**
     * 参数:
     * proxy 被代理对象
     * method 被代理对象方法
     * args 方法的参数
     * 返回值:
     * Object 方法的返回值
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        long starttime = System.currentTimeMillis();
        System.out.println("汽车开始行驶...");
        
        method.invoke(target);
        
        long endtime = System.currentTimeMillis();
        System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
        
        return null;
    }

}

2.编写Test类

package com.myimooc.designpattern.c3proxy.jdk;

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

import com.myimooc.designpattern.c3proxy.car.Car;
import com.myimooc.designpattern.c3proxy.car.Moveable;

/**
 * @describe JDK动态代理测试类
 * @author zc
 * @version 1.0 2017-08-28
 */
public class Test {
    
    public static void main(String[] args) {
        Car car = new Car();
        InvocationHandler h = new TimeHandler(car);
        Class cls = car.getClass();
        
        // 使用Proxy类newProxyInstance方法动态创建代理类
        /**
         * loader 类加载器
         * interfaces 实现接口
         * h InvocationHandler
         */
        Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);
        
        m.move();
        
    }
    
}
2-4 使用cglib

JDK动态代理与CGLIB动态代理区别

JDK动态代理
1.只能代理实现了接口的类
2.没有实现接口的类不能实现JDK的动态代理
CGLIB动态代理
1.针对类来实现代理的
2.对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用
3.因为是使用继承的方式,所以不能对final修饰的类来进行代理

代码编写

1.添加相关依赖

      
    
        cglib
        cglib-nodep
        3.2.5
    
      
    
        commons-io
        commons-io
        2.5
    

2.编写CglibProxy类

package com.myimooc.designpattern.c3proxy.cglib;

import java.lang.reflect.Method;

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

/**
 * @describe 代理类
 * @author zc
 * @version 1.0 2017-08-28
 */
public class CglibProxy implements MethodInterceptor {
    
    private Enhancer enhance = new Enhancer();
    
    @SuppressWarnings("rawtypes")
    public Object getProxy(Class clazz){
        // 设置创建子类的类
        enhance.setSuperclass(clazz);
        enhance.setCallback(this);
        return enhance.create();
    }

    /**
     * 拦截所有目标类方法的调用
     * 参数:
     * obj 目标类的实例
     * method 目标方法的反射对象
     * args 方法的参数
     * proxy 代理类的实例
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        
        System.out.println("日志开始...");
        
        // 代理类调用父类的方法
        proxy.invokeSuper(obj, args);
        
        System.out.println("日志结束...");
        
        return null;
    }

}

3.编写Train类

package com.myimooc.designpattern.c3proxy.cglib;

/**
 * @describe 火车
 * @author zc
 * @version 1.0 2017-08-28
 */
public class Train {
    
    public void move(){
        System.out.println("火车行驶中");
    }
    
}

4.编写Client类

package com.myimooc.designpattern.c3proxy.cglib;


/**
 * @describe cglib代理测试类
 * @author zc
 * @version 1.0 2017-08-28
 */
public class Client {
    
    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        Train t = (Train)proxy.getProxy(Train.class);
        t.move();
    }
}
第三章:模拟JDK动态代理 3-1 实现动态代理

动态代理实现思路

实现功能:通过Proxy的newProxyInstance返回代理对象
1.声明一段源码(动态产生代理)
2.编译编码(JDK Compiler API),产生新的类(代理类)
3.将这个类load到内存当中,产生一个新的对象(代理对象)
4.return 代理对象

代码编写

1.编写InvocationHandler类

package com.myimooc.designpattern.c3proxy.simulationjdk;

import java.lang.reflect.Method;

/**
 * @describe 模拟JDK动态代理-业务处理类
 * @author zc
 * @version 1.0 2017-08-28
 */
public interface InvocationHandler {
    
    public void invoke(Object obj,Method method);
    
}

2.编写Proxy类

package com.myimooc.designpattern.c3proxy.simulationjdk;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

import org.apache.commons.io.FileUtils;

/**
 * @describe 模拟JDK动态代理-代理类
 * @author zc
 * @version 1.0 2017-08-28
 */
@SuppressWarnings({"rawtypes","unchecked"})
public class Proxy {
    
    public static Object newProxyInstance( Class infce,InvocationHandler h)throws Exception{
        String rt = "
";
        String methodStr = "";
        for(Method m : infce.getMethods()){
            methodStr += "    @Override" + rt +
            "    public void "+ m.getName() +"(){" + rt +
            "     try{" + rt +
            "        Method md = " +infce.getName()+".class.getMethod(""+m.getName()+"");" + rt +
            "        h.invoke(this,md);" + rt +
            "     }catch(Exception e){e.printStackTrace();}" + rt +
            "    }" + rt;
        }
        
        String str =
        "package com.myimooc.designpattern.c3proxy.simulationjdk; " + rt +
        "import com.myimooc.designpattern.c3proxy.simulationjdk.InvocationHandler;" + rt +
        "import java.lang.reflect.Method;" + rt +
        "public class $Proxy0 implements "+ infce.getName() +" { " + rt +
        "    public $Proxy0(InvocationHandler h) {" + rt +
        "        this.h = h;" + rt +
        "    }" + rt +
        "    private InvocationHandler h;" + rt +
        methodStr + rt +
        "}";
        
        // 产生代理类的java文件
        String filename = System.getProperty("user.dir") + "/target/classes/com/myimooc/designpattern/c3proxy/simulationjdk/$Proxy0.java";
        File file = new File(filename);
        FileUtils.writeStringToFile(file, str,"UTF-8");
        
        // 编译-拿到编辑器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        // 文件管理者
        StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
        // 获取文件
        Iterable units = fileMgr.getJavaFileObjects(filename);
        // 编译任务
        CompilationTask task = compiler.getTask(null, fileMgr, null, null, null, units);
        // 进行编译
        task.call();
        fileMgr.close();
        
        // load到内存
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        Class c = cl.loadClass("com.myimooc.designpattern.c3proxy.simulationjdk.$Proxy0");
        
        Constructor ctr = c.getConstructor(InvocationHandler.class);
        return ctr.newInstance(h);
    }
}

3.编写TimeHandler类

package com.myimooc.designpattern.c3proxy.simulationjdk;

import java.lang.reflect.Method;

/**
 * @describe 模拟JDK动态代理-时间业务逻辑处理
 * @author zc
 * @version 1.0 2017-08-28
 */
public class TimeHandler implements InvocationHandler{
    
    private Object target;
    
    public TimeHandler(Object target) {
        super();
        this.target = target;
    }

    @Override
    public void invoke(Object obj, Method method) {
        try {
            
            long starttime = System.currentTimeMillis();
            System.out.println("汽车开始行驶...");
            
            method.invoke(target);
            
            long endtime = System.currentTimeMillis();
            System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.编写Client类

package com.myimooc.designpattern.c3proxy.simulationjdk;

import com.myimooc.designpattern.c3proxy.car.Car;
import com.myimooc.designpattern.c3proxy.car.Moveable;

/**
 * @describe 模拟JDK动态代理-测试类
 * @author zc
 * @version 1.0 2017-08-28
 */
public class Client {
    
    public static void main(String[] args) throws Exception {
        Car car = new Car();
        InvocationHandler h = new TimeHandler(car);
        Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class,h);
        m.move();
    }
}
第四章:总结 4-1 课程总结

总结

代理模式概念、分类及应用场景
场景代理模式
静态代理(继承、聚合)
JDK动态代理实现日志处理功能
模拟JDK动态代理实现

代理模式-动态代理

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70297.html

相关文章

  • 课网_模式秘密责任链模式学习总结

    时间:2017年08月30日星期三说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学源码:https://github.com/zccodere/s...学习源码:https://github.com/zccodere/s... 第一章:责任链模式简介 1-1 课程简介 课程大纲 什么是责任链模式 如何实现责任链模式 责任链模式如何解耦 责任链模式的应用 案例:...

    jsyzchen 评论0 收藏0
  • 课网_模式秘密单例模式学习总结

    时间:2017年08月27日星期日说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学源码:https://github.com/zccodere/s...学习源码:https://github.com/zccodere/s... 第一章:单例模式简介 1-1 简介 单例模式 概念及应用场合 饿汉模式 懒汉模式 饿汉模式与懒汉模式的区别 什么是设计模式 是一套被反...

    afishhhhh 评论0 收藏0
  • 课网_模式秘密策略模式学习总结

    时间:2017年08月31日星期四说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学源码:https://github.com/zccodere/s...学习源码:https://github.com/zccodere/s... 第一章:策略模式简介 1-1 简介 课程大纲 什么是策略模式 策略模式如何实现 策略模式总结篇 实例案例分享 日常生活中的策略 Wor...

    zhongmeizhi 评论0 收藏0
  • 课网_模式秘密适配器模式学习总结

    摘要:时间年月日星期二说明本文部分内容均来自慕课网。慕课网教学源码学习源码第一章适配器模式的简介简介生活中的适配器翻译软件插座适配器适配器模式定义适配器模式讲将一个类的接口,转换成客户期望的另外一个接口。 时间:2017年08月29日星期二说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学源码:https://github.com/zccodere/s.....

    andong777 评论0 收藏0
  • 课网_模式秘密模版模式学习总结

    摘要:时间年月日星期六说明本文部分内容均来自慕课网。案例介绍饮料机配置模版把水煮沸泡饮料把饮料倒进杯子加调味料第二章模版模式实现基本框架代码编写编写类模版模式抽象基类,为所有子类提供一个算法框架。 时间:2017年09月02日星期六说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学源码:https://github.com/zccodere/s...学习源...

    Hancock_Xu 评论0 收藏0

发表评论

0条评论

wow_worktile

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<