时间: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.添加相关依赖
<!-- https://mvnrepository.com/artifact/cglib/cglib-nodep -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.2.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
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 = "\r\n";
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动态代理实现
代理模式-动态代理
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。