设计模式

代理模式

一、代理模式的基本概念与分类

代理的定义:为其他对象提供一种代理,以控制对这个对象的访问。
常见的代理模式有:远程代理、虚拟代理、保护代理、智能引用代理。

二、常用代理模式原理

下面以智能引用代理来介绍静态代理模式与动态代理模式。
静态代理:代理和被代理对象在代理之前是确定的。他们都实现了相同的接口或继承了相同的抽象类。
有这样一个需求:有一辆小汽车,有一个行驶的方法move,还需要一个记录行驶时间的方法。
方案一:
1
2
3
public interface Moveable {
public void move();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

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) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("汽车形式结束.....,汽车形式时间:"+(endTime-startTime));
}
}
方案二:通过继承的方式实现静态代理实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Car implements Moveable {
@Override
public void move() {

//实现开车
try {
System.out.println("汽车形式中......");
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}

}
}
1
2
3
4
5
6
7
8
9
10
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));
}
}

方案三:聚合的方式实现静态代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Car implements Moveable {
@Override
public void move() {

//实现开车
try {
System.out.println("汽车形式中......");
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Car3 extends Car  {
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));
}
}
1
2
3
4
5
6
7
8
public class main {
public static void main(String[] args) {
Car car = new Car();
// car.move();
Car3 car3 = new Car3(car);
car3.move();
}
}
汽车形式开始.......
汽车形式中......
汽车形式结束.....,汽车形式时间:48

那么继承与聚合的方式实现静态代理,谁更好呢?
那么现在又有需要,在move方法前不紧有记录时间的功能,还有权限的功能,记录日志的功能:如先日志-->权限,权限-->日志,用继承方式实现难道要继续新建Car4、Car5?那么聚合就不用么?看如下实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Car implements Moveable {
@Override
public void move() {

//实现开车
try {
System.out.println("汽车形式中......");
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class CarLogProxy implements Moveable {

public CarLogProxy(Moveable m) {
super();
this.m = m;
}

private Moveable m;
@Override
public void move() {
System.out.println("日志记录开始.....");
m.move();
System.out.println("记录日志结束......");

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class CarTimeProxy implements 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));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class main {
public static void main(String[] args) {
Car car = new Car();

CarTimeProxy carTimeProxy = new CarTimeProxy(car);
CarLogProxy logProxy = new CarLogProxy(carTimeProxy);
logProxy.move();
System.out.println("-----------------------------");
CarLogProxy logProxy1 = new CarLogProxy(car);
CarTimeProxy carTimeProxy1 = new CarTimeProxy(logProxy1);

carTimeProxy1.move();

}
}
日志记录开始.....
汽车形式开始.......
汽车形式中......
汽车形式结束.....,汽车形式时间:767
记录日志结束......
-----------------------------
汽车形式开始.......
日志记录开始.....
汽车形式中......
记录日志结束......
汽车形式结束.....,汽车形式时间:288


这样就决解了上面的问题,但是如果我们又要为火车,公交车、飞机实现这样的功能呢,难道又要新建TrainTimePoxy,TrainLogPoxy,BusTimeProxy........?这个时候动态代理就出现了。

三、理解JDK动态代理实现

image

Java动态代理位于java.lang.reflect包下,,一般主要涉及两个类:
    (1)、Interface InvocationHandler:该接口中仅定义了一个方法:public Object invoke(Object proxy, Method method, Object[] args),
    在实际的使用中,第一个参数obj一般指被代理类,method指被代理的方法,arg代理方法的参数。
    (2)、该类即为动态代理类:static newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在接口中声明的方法)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class TimeHandler implements InvocationHandler{

public TimeHandler(Object target) {
super();
this.target = target;
}

private Object target;

/**
*
* @param proxy:被代理的对象
* @param method:被代理对象的方法
* @param args:方法的参数
* @return:Object对象,方法的返回值
* @throws Throwable
*/
@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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class main {
public static void main(String[] args) {
Car car = new Car();
Class c = car.getClass();
InvocationHandler h = new TimeHandler(car);

/**
* loader:类加载器
* interfaces:实现的接口
* h:InvocationHander
*/
Moveable m = (Moveable) Proxy.newProxyInstance(c.getClassLoader(),c.getInterfaces(),h);
m.move();

}
}
汽车形式开始.......
汽车形式中......
汽车形式结束.....,汽车形式时间:432


总结:所谓的Dynamic Proxy是这样一种class:
它是在运行时生产的Class;
该class需要实现一组interface;
使用动态代理时,需要实现InvocationHandler接口;

实现动态代理的步骤:
(1)、创建一个实现InvocationHandler的类,他必须实现invoke()方法;
(2)、创建被代理的类以及接口;
(3)、调用Proxy的静态方法,创建一个代理类,Proxy.newProxyInstance(c.getClassLoader(),c.getInterfaces(),h)
(4)、通过代理调用方法。

四、JAK动态代理实现原理分析

文章目录
  1. 1. 一、代理模式的基本概念与分类
  2. 2. 二、常用代理模式原理
    1. 2.0.0.0.1. 方案一:
    2. 2.0.0.0.2. 方案二:通过继承的方式实现静态代理实现:
  • 3. 三、理解JDK动态代理实现
  • 4. 四、JAK动态代理实现原理分析