Fork me on GitHub

设计模式———代理模式

代理模式:在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。按照代理的创建时期,一般分为两类:静态代理和动态代理。

静态代理:由程序员或特定工具自动生成的源代码,再对其编译,在程序运行之前,代理的类编译生成的.class文件就已经存在了

动态代理:在程序运行时,通过反射机制动态创建而成。

介绍:为其他对象提供一种代理以控制对这个对象的访问,在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

应用实例:JDK动态代理是代理模式的一种实现方式,其只能代理接口。Spring的一大思想AOP原理就是Java的动态代理机制。jdk动态代理和cglib动态代理。两种方法的存在,各有各自的优势。jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现。

动态代理主要实现使用的是聚合,这种方法更有利于继承

作用:

(1)方法前后加日志,记录时间(方法运行的时间)

(2)方法前后加事务,事务的提交或者回滚(AOP)

(3)方法前后加判断调用者是否拥有权限,用于权限的控制

静态代理:

接口

1
2
3
4
public interface Moveable {

void move();
}

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14

public class Tank implements Moveable
{
@Override
public void move() {
System.out.println("Tank Moving...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}

日志代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
public class TankLogProxy implements Moveable {
public TankLogProxy(Moveable t) {
super();
this.t = t;
}
Moveable t;
@Override
public void move() {
System.out.println("log Start ...");
t.move();
System.out.println("log end ...");
}
}

时间代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TankTimeProxy implements Moveable {	
public TankTimeProxy(Moveable t) {
super();
this.t = t;
}
Moveable t;
@Override
public void move() {
long start = System.currentTimeMillis();
t.move();
long end = System.currentTimeMillis();
System.out.println("运行时间:"+(end-start)/1000+"秒");
}
}

测试类

1
2
3
4
5
6
7
8
9
public class TestProxy {	
public static void main(String[] args)
Tank t = new Tank();
TankTimeProxy ttp = new TankTimeProxy(t)
TankLogProxy tlp = new TankLogProxy(ttp);
Moveable m = tlp;
m.move();
}
}

动态代理:

  1. 需要存在抽象对象,定义所有的功能
  2. 真实对象实现抽象对象所有的功能
  3. 通过Proxy类,创建代理对象,调用代理方法
  4. 在InvocationHandler的invoke对代理的方法有选择的修改或不修改真实对象原有的方法。

抽象角色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
抽象角色:定义功能
*/
public interface Star {
/**
唱歌
@param song
*/
void sing(String song);
/**
演出
@param money
*/
void act(int money);
}

具体角色

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
真实角色
*/
public class SuperStar implements Star {
@Override
public void sing(String song) {
System.out.println("明星唱:" + song);
}
@Override
public void act(int money) {
System.out.println("明星拍戏出场费:" + money);
}
}

jdk动态代理角色

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.it.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Fans {

public static void main(String[] args) {
  /*
  使用JDK动态代理,创建代理对象
  参数1:类加载器
  参数2:所有实现的接口
  参数3:方法调用的接口,Star接口中每个方法都会调用一次
  */
  Star s2 = (Star) Proxy.newProxyInstance(
    s1.getClass().getClassLoader(),
    new Class[]{Star.class},
  new InvocationHandler() {
/*
对每个方法进行功能增强
参数1:代理对象,不能直接调用,不然出现递归
参数2:每个方法对象,如:sing() act(),每个方法都会调用一次
参数3:方法传递的参数,如:歌名
返回值:调用的方法的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  //如果是演出的方法,判断是否小于1000,如果小于则不演出,否则调用原来的方法
  String methodName = method.getName();
  if ("act".equals(methodName)) {
  //得到演示参数值
  int money = (int) args[0];
  if (money < 1000) {
    System.out.println("费用太低,不演出了");
  return null;
  }
}
  //其它的情况就调用真实对象原来的方法
  return method.invoke(s1, args); //真实对象,方法的参数
  }
});

  //fans请自己喜欢的明星出场唱歌,拍戏
  s2.sing("只因你太美");
  //费用过低不满足
  s2.act(500);

  }
}