Skip to content

Commit bc54547

Browse files
committed
设计模式-代理模式
1 parent 716f2dd commit bc54547

File tree

10 files changed

+314
-0
lines changed

10 files changed

+314
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.design.proxy;
2+
3+
/**
4+
* 媒体接口
5+
*/
6+
public interface Media {
7+
8+
void play(String file);
9+
10+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.design.proxy;
2+
3+
/**
4+
* 直接的电影媒体类
5+
*/
6+
public class MovieMedia {
7+
8+
public void play(String file) {
9+
System.out.println("Play Movie: " + file);
10+
}
11+
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.design.proxy;
2+
3+
/**
4+
* 实现媒体接口 - 音乐媒体
5+
*/
6+
public class MusicMediaImpl implements Media {
7+
8+
@Override
9+
public void play(String file) {
10+
System.out.println("Play Music: " + file);
11+
}
12+
13+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.design.proxy.v1;
2+
3+
import com.design.proxy.Media;
4+
import com.design.proxy.MusicMediaImpl;
5+
6+
/**
7+
* 静态代理事先知道要代理的是什么,目标角色固定不灵活
8+
*
9+
* @author wliduo[i@dolyw.com]
10+
* @date 2023/1/31 16:41
11+
*/
12+
public class Main {
13+
14+
public static void main(String[] args) {
15+
// 组合嵌套多个代理类
16+
Media musicMedia = new MusicMediaImpl();
17+
// musicMedia.play("音乐");
18+
Media proxyMedia = new ProxyMediaImpl(musicMedia);
19+
// proxyMedia.play("音乐");
20+
Media timeProxyMedia = new TimeProxyMediaImpl(proxyMedia);
21+
timeProxyMedia.play("音乐");
22+
}
23+
24+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.design.proxy.v1;
2+
3+
import com.design.proxy.Media;
4+
5+
/**
6+
* 静态代理一
7+
*
8+
* @author wliduo[i@dolyw.com]
9+
* @date 2023/1/31 16:43
10+
*/
11+
public class ProxyMediaImpl implements Media {
12+
13+
Media media;
14+
15+
public ProxyMediaImpl(Media media) {
16+
this.media = media;
17+
}
18+
19+
@Override
20+
public void play(String file) {
21+
System.out.println("Start");
22+
media.play(file);
23+
System.out.println("End");
24+
}
25+
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.design.proxy.v1;
2+
3+
import com.design.proxy.Media;
4+
5+
/**
6+
* 静态代理二
7+
*
8+
* @author wliduo[i@dolyw.com]
9+
* @date 2023/1/31 16:43
10+
*/
11+
public class TimeProxyMediaImpl implements Media {
12+
13+
Media media;
14+
15+
public TimeProxyMediaImpl(Media media) {
16+
this.media = media;
17+
}
18+
19+
@Override
20+
public void play(String file) {
21+
System.out.println(System.currentTimeMillis());
22+
media.play(file);
23+
System.out.println(System.currentTimeMillis());
24+
}
25+
26+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.design.proxy.v2;
2+
3+
import com.design.proxy.MovieMedia;
4+
import com.design.proxy.MusicMediaImpl;
5+
import org.springframework.cglib.proxy.Enhancer;
6+
import org.springframework.cglib.proxy.MethodInterceptor;
7+
import org.springframework.cglib.proxy.MethodProxy;
8+
9+
import java.lang.reflect.Method;
10+
11+
/**
12+
* CGLib必须依赖于CGLib的类库,需要满足以下要求
13+
* 1. 实现MethodInterceptor接口,重写intercept()
14+
* 2. 使用Enhancer对象.create()产生代理对象
15+
* 3. 因为是继承机制,不能代理final修饰的类
16+
*
17+
* CGLIB则使用的继承机制,针对类实现代理,被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的
18+
* CGLIB代理使用字节码处理框架asm,对代理对象类的class文件加载进来,通过修改字节码生成子类
19+
* CGLIB创建代理对象效率较低,执行效率高
20+
*
21+
* @author wliduo[i@dolyw.com]
22+
* @date 2023/1/31 16:52
23+
*/
24+
public class CglibDynamicProxy implements MethodInterceptor {
25+
26+
/**
27+
* 代理的目标对象
28+
*/
29+
private Object object;
30+
31+
public CglibDynamicProxy(Object object) {
32+
this.object = object;
33+
}
34+
35+
public Object proxy() {
36+
Class<?> clazz = object.getClass();
37+
// 生成代理对象
38+
Enhancer enhancer = new Enhancer();
39+
enhancer.setSuperclass(clazz);
40+
enhancer.setCallback(this);
41+
return enhancer.create();
42+
}
43+
44+
@Override
45+
public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
46+
System.out.println(proxy.getClass().getSuperclass().getName());
47+
beforeMethod(object);
48+
Object result = methodProxy.invokeSuper(proxy, objects);
49+
afterMethod(object);
50+
return result;
51+
}
52+
53+
private void beforeMethod(Object object) {
54+
if (object instanceof MusicMediaImpl) {
55+
System.out.println("MusicMediaImpl Start");
56+
} else if (object instanceof MovieMedia) {
57+
System.out.println("MovieMedia Start");
58+
} else {
59+
throw new RuntimeException("暂不支持代理" + object.getClass() + "类型");
60+
}
61+
}
62+
63+
private void afterMethod(Object object) {
64+
if (object instanceof MusicMediaImpl) {
65+
System.out.println("MusicMediaImpl End");
66+
} else if (object instanceof MovieMedia) {
67+
System.out.println("MovieMedia End");
68+
} else {
69+
throw new RuntimeException("暂不支持代理" + object.getClass() + "类型");
70+
}
71+
}
72+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.design.proxy.v2;
2+
3+
import com.design.proxy.MovieMedia;
4+
import com.design.proxy.MusicMediaImpl;
5+
6+
import java.lang.reflect.InvocationHandler;
7+
import java.lang.reflect.Method;
8+
import java.lang.reflect.Proxy;
9+
10+
/**
11+
* JDK代理是不需要依赖第三方的库,只要JDK环境就可以进行代理,需要满足以下要求
12+
* 1. 实现InvocationHandler接口,重写invoke()
13+
* 2. 使用Proxy.newProxyInstance()产生代理对象
14+
* 3. 被代理的对象必须要实现接口
15+
*
16+
* JDK动态代理机制是委托机制,只能对实现接口的类生成代理,通过反射动态实现接口类
17+
* JDK代理使用的是反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理
18+
* JDK创建代理对象效率较高,执行效率较低
19+
*
20+
* @author wliduo[i@dolyw.com]
21+
* @date 2023/1/31 16:52
22+
*/
23+
public class JdkDynamicProxy implements InvocationHandler {
24+
25+
/**
26+
* 代理的目标对象
27+
*/
28+
private Object object;
29+
30+
public JdkDynamicProxy(Object object) {
31+
this.object = object;
32+
}
33+
34+
public Object proxy() {
35+
Class<?> clazz = object.getClass();
36+
// 生成代理对象
37+
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
38+
}
39+
40+
@Override
41+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
42+
beforeMethod(object);
43+
Object result = method.invoke(object, args);
44+
afterMethod(object);
45+
return result;
46+
}
47+
48+
private void beforeMethod(Object object) {
49+
if (object instanceof MusicMediaImpl) {
50+
System.out.println("MusicMediaImpl Start");
51+
} else if (object instanceof MovieMedia) {
52+
System.out.println("MovieMedia Start");
53+
} else {
54+
throw new RuntimeException("暂不支持代理" + object.getClass() + "类型");
55+
}
56+
}
57+
58+
private void afterMethod(Object object) {
59+
if (object instanceof MusicMediaImpl) {
60+
System.out.println("MusicMediaImpl End");
61+
} else if (object instanceof MovieMedia) {
62+
System.out.println("MovieMedia End");
63+
} else {
64+
throw new RuntimeException("暂不支持代理" + object.getClass() + "类型");
65+
}
66+
}
67+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.design.proxy.v2;
2+
3+
import com.design.proxy.Media;
4+
import com.design.proxy.MovieMedia;
5+
import com.design.proxy.MusicMediaImpl;
6+
7+
/**
8+
* 相比于静态代理,动态代理在创建代理对象上更加的灵活
9+
*
10+
* 验证一,音乐媒体类实现接口都可以成功代理
11+
*
12+
* @author wliduo[i@dolyw.com]
13+
* @date 2023/1/31 16:55
14+
*/
15+
public class Main {
16+
17+
public static void main(String[] args) {
18+
Media musicMedia = new MusicMediaImpl();
19+
// musicMedia.play("音乐");
20+
// 使用Jdk动态代理接口实现方式
21+
JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy(musicMedia);
22+
Media jdkDynamicProxyMedia = (Media) jdkDynamicProxy.proxy();
23+
jdkDynamicProxyMedia.play("Jdk音乐");
24+
25+
System.out.println("----------");
26+
27+
// 使用Cglib动态代理接口实现方式
28+
CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy(musicMedia);
29+
Media cglibDynamicProxyMedia = (Media) cglibDynamicProxy.proxy();
30+
cglibDynamicProxyMedia.play("Cglib音乐");
31+
}
32+
33+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.design.proxy.v2;
2+
3+
import com.design.proxy.MovieMedia;
4+
5+
/**
6+
* 相比于静态代理,动态代理在创建代理对象上更加的灵活
7+
*
8+
* 验证二,电影媒体类未实现接口只有Cglib可以代理
9+
*
10+
* @author wliduo[i@dolyw.com]
11+
* @date 2023/1/31 16:55
12+
*/
13+
public class Main2 {
14+
15+
public static void main(String[] args) {
16+
MovieMedia movieMedia = new MovieMedia();
17+
// movieMedia.play("电影");
18+
// 使用Cglib动态代理Class类
19+
CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy(movieMedia);
20+
MovieMedia cglibDynamicProxyMedia = (MovieMedia) cglibDynamicProxy.proxy();
21+
cglibDynamicProxyMedia.play("Cglib电影");
22+
23+
System.out.println("----------");
24+
25+
// 使用Jdk动态代理Class类,运行失败,Jdk必须实现接口才可以代理
26+
JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy(movieMedia);
27+
MovieMedia jdkDynamicProxyMedia = (MovieMedia) jdkDynamicProxy.proxy();
28+
jdkDynamicProxyMedia.play("Jdk电影");
29+
}
30+
31+
}

0 commit comments

Comments
 (0)