设计模式-代理模式

定义

代理模式是一种结构型设计模式, 让你能够提供对象的替代品。 代理控制着对原对象的访问, 并允许在将请求提交给对象前后进行一些处理。

静态代理

这种代理方式需要代理对象和目标对象实现一样的接口。优点:可以在不修改目标对象的前提下扩展目标对象的功能。缺点:扩展被代理类功能时会产生过多的代理类,如果目标接口修改,所有类包括代理类都要修改。

静态代理的两种实现方式:1、继承,2、组合

先定义目标类和接口如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface Flyable {
void fly();
}

public class Bird implements Flyable {
private static Logger logger = LoggerFactory.getLogger(Bird.class);
@Override
public void fly() {
logger.info ( "Bird flying" );
try {
Thread.sleep ( new Random ( ).nextInt (100) );
} catch (Exception e) {
e.printStackTrace ();
}
}

}

继承

通过继承的方式来新建两个代理类统计时间和记录Log,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class BirdFlyTime extends Bird {
private static Logger logger = LoggerFactory.getLogger ( BirdFlyTime.class );
@Override
public void fly() {
long start = System.currentTimeMillis ();
super.fly ();
long end = System.currentTimeMillis ();
logger.info ( "Bird flying time: {}", end - start );
}
}

public class BirdLog extends Bird {
private static Logger logger = LoggerFactory.getLogger ( BirdLog.class );

@Override
public void fly() {
logger.info ( "Bird fly start..." );
super.fly ();
logger.info ( "Bird fly end..." );
}
}

使用继承代理:可知使用继承实现的静态代理,不能同时使用

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
Bird bird = new Bird ();

//使用继承实现的静态代理,不能同时使用
BirdLog birdLog = new BirdLog ();
birdLog.fly ();

BirdFlyTime birdFlyTime = new BirdFlyTime ();
birdFlyTime.fly ();
}

组合

通过组合的方式来新建两个代理类统计时间和记录Log,

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
public class BirdFlyTimeProxy implements Flyable {
private static Logger logger = LoggerFactory.getLogger ( BirdFlyTimeProxy.class );
private Flyable flyable;

public BirdFlyTimeProxy(Flyable flyable) {
this.flyable = flyable;
}

@Override
public void fly() {
long start = System.currentTimeMillis ();
logger.info ( "Bird flying start time: {}", start );
flyable.fly ();
long end = System.currentTimeMillis ();
logger.info ( "Bird flying end time: {}", end );
}
}

public class BirdLogProxy implements Flyable {
private static Logger logger = LoggerFactory.getLogger ( BirdLogProxy.class );
private Flyable flyable;

public BirdLogProxy(Flyable flyable) {
this.flyable = flyable;
}

@Override
public void fly() {
logger.info ( "Bird fly start..." );
flyable.fly ();
logger.info ( "Bird fly end..." );
}
}

使用组合代理:可知使用组合实现的静态代理可以同时使用并灵活调换代理的执行顺序

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
Bird bird = new Bird ();

//使用组合实现的静态代理可以同时使用并灵活调换代理的执行顺序
BirdLogProxy birdLogProxy1 = new BirdLogProxy ( bird );
BirdFlyTimeProxy birdFlyTimeProxy1 = new BirdFlyTimeProxy ( birdLogProxy1 );
birdFlyTimeProxy1.fly ();

BirdFlyTimeProxy birdFlyTimeProxy2 = new BirdFlyTimeProxy ( bird );
BirdLogProxy birdLogProxy2 = new BirdLogProxy ( birdFlyTimeProxy2 );
birdLogProxy2.fly ();
}

动态代理

相对于静态代理需要手动书写代理类然后编译生成class文件载入JVM运行,动态代理是在JVM运行起来以后在内存中动态的创建代理类class文件(字节流)并载入JVM执行。

动态代理又分为JDK动态代理和CGLIB动态代理。

JDK动态代理

要使用JDK动态代理有一个前提,要求被代理的目标类必须实现接口。JDK动态代理可以看作组合型静态代理的扩展,它封装了具体的被代理目标类,提供一个统一的接口InvocationHandler,让代理类实现这个接口即可,实现了对所有不同目标类的代理功能。

还是以上面Flyable接口+Bird类举例使用JDK代理。

首先代理类需要实现InvocationHandler接口

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
public class BirdLogProxy implements InvocationHandler {
private static Logger logger = LoggerFactory.getLogger ( BirdLogProxy.class );
private Object object;

public BirdLogProxy(Object object) {
this.object = object;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
logger.info ( "Bird fly start..." );
method.invoke ( object, args);
logger.info ( "Bird fly end..." );
return null;
}
}

public class BirdFlyTimeProxy implements InvocationHandler {
private static Logger logger = LoggerFactory.getLogger ( BirdFlyTimeProxy.class );
private Object object;

public BirdFlyTimeProxy(Object object) {
this.object = object;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis ();
logger.info ( "Bird flying start time: {}", start );
method.invoke ( object, args );
long end = System.currentTimeMillis ();
logger.info ( "Bird flying end time: {}", end );
return null;
}
}

然后根具体的目标类绑定,调用Proxy.newProxyInstance即可生成代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
public class JDKProxyUsage {
public static void main(String[] args) {
Bird bird = new Bird ();

BirdLogProxy birdLogProxy = new BirdLogProxy ( bird );
Flyable flyable = (Flyable) Proxy.newProxyInstance ( bird.getClass ().getClassLoader (), bird.getClass ().getInterfaces (), birdLogProxy );
flyable.fly ();

BirdFlyTimeProxy birdFlyTimeProxy = new BirdFlyTimeProxy ( bird );
flyable = (Flyable) Proxy.newProxyInstance ( bird.getClass ().getClassLoader (), bird.getClass ().getInterfaces (), birdFlyTimeProxy );
flyable.fly ();
}
}

CGLIB动态代理

CGLIB是一个第三方代码生成类库,它的底层是通过使用一个字节码处理框架ASM,来转换字节码并生成新的类。CGLIB动态代理和JDK动态代理的区别是:CGLIB对被代理的目标类没有必须要实现接口的要求,只要目标类不是final类即可,由此可见CGLIB是使用继承的方式来实现代理类的。

还是以上面Flyable接口+Bird类举例使用CGLIB代理。

首先代理类需要实现MethodInterceptor接口(此处使用了单例模式),通过getProxy方法即可生成代理类

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
public class BirdLogProxy implements MethodInterceptor{
private static Logger logger = LoggerFactory.getLogger ( BirdLogProxy.class );
private static BirdLogProxy cglibProxy = new BirdLogProxy ();
private BirdLogProxy() {}

public static BirdLogProxy getInstance() {
return cglibProxy;
}

public <T> T getProxy(Class<T> clazz) {
return (T) Enhancer.create ( clazz, this );
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
logger.info ( "Bird fly start..." );
methodProxy.invokeSuper ( o, objects );
logger.info ( "Bird fly end..." );
return null;
}
}


public class BirdFlyTimeProxy implements MethodInterceptor{
private static Logger logger = LoggerFactory.getLogger ( BirdFlyTimeProxy.class );
private static BirdFlyTimeProxy cglibProxy = new BirdFlyTimeProxy ();
private BirdFlyTimeProxy() {}

public static BirdFlyTimeProxy getInstance() {
return cglibProxy;
}

public <T> T getProxy(Class<T> clazz) {
return (T) Enhancer.create ( clazz, this );
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
long start = System.currentTimeMillis ();
logger.info ( "Bird flying start time: {}", start );
methodProxy.invokeSuper ( o, objects );
long end = System.currentTimeMillis ();
logger.info ( "Bird flying end time: {}", end );
return null;
}
}

使用CGLIB代理如下

1
2
3
4
5
6
7
public static void main(String[] args) {
Bird bird = BirdLogProxy.getInstance ().getProxy ( Bird.class );
bird.fly ();

bird = BirdFlyTimeProxy.getInstance ().getProxy ( Bird.class );
bird.fly ();
}
-------------本文结束感谢您的阅读-------------
Good for you!