初学Java代理机制,看了好几篇博客终于有点感觉,用我自己的理解写了篇总结,如有不对的地方,欢迎大佬指正。

什么是代理

我的理解就是给这段程序请了一个”经纪人”,执行的时候还是这段程序来执行,只不过前后有些事务可以交给”经纪人”打理,就像明星的经纪人一样,帮明星打理一些事情,唱歌、演戏还得由明星自己去做。

静态代理

我以主播为例。

主播最主要的工作就是直播,所以定义一个接口。

1
2
3
interface Streamer {
public void work();
}

主播里面主要有游戏主播,唱歌主播等,所以先定义两个类实现主播这个接口

1
2
3
4
5
6
7
8
9
10
11
12
13
class GameStreamer implements Streamer{
@Override
public void work() {
System.out.println("直播打游戏");
}
}

class SingerStreamer implements Streamer{
@Override
public void work() {
System.out.println("直播唱歌");
}
}

好了,现在游戏主播越来越火,需要处理的事情也越来越多,比如:签合同,抽奖,微博、公众号互动,开淘宝店等等。他觉得很烦,所以请了个经纪人或者找了一个公司又或者组了个团队,总之就是一个代理,专门帮他运营这些杂事,他就只负责做好直播就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class StreamerProxy implements Streamer{
private Streamer streamer;

public StreamerProxy(Streamer streamer){
this.streamer = streamer;
}

@Override
public void work() {
beforeWork();
streamer.work();
afterWork();
}

private void beforeWork(){
System.out.println("帮客户签合同");
System.out.println("发布公告");
}

private void afterWork(){
System.out.println("抽奖");
System.out.println("开淘宝店");
}
}

测试类

1
2
3
4
5
6
7
public class ProxyTest {
public static void main(String[] args) {
Streamer gameStreamer = new GameStreamer();
StreamerProxy streamerProxy = new StreamerProxy(gameStreamer);
streamerProxy.work();
}
}

结果

1
2
3
4
5
帮客户签合同
发布公告
直播打游戏
抽奖
开淘宝店

同样,不管是什么主播,唱歌主播,还是户外主播,只要他找了代理,就能帮他完成除直播外的一些额外的主播之间相同的工作。

当然,代理想要赚更多钱。你不是主播,你有流量,我也可以帮你做这些事啊。不过,就要重新按照上面的流程,定义接口,实现类,定义代理,再来一遍,但是代理做的工作是一样的。为了减少代码量,实现灵活处理,就有了动态代理。

动态代理

动态代理有两种实现方法,一种是JDK自带的,通过实现InvocationHandler接口,另一种是采用开源项目cglib

JDK动态代理

定义另外一个微博大V接口及实现类

1
2
3
4
5
6
7
8
9
10
11
12
//微博大V
interface WeiboBigV{
public void post();
}

//网红大V
class BeautyBigV implements WeiboBigV{
@Override
public void post() {
System.out.println("上传美照");
}
}

实现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
class DynamicProxy implements InvocationHandler {

//被代理对象
private Object person;

public DynamicProxy(Object person) {
this.person = person;
}

//返回一个代理对象
public Object getNewInstance() {
return Proxy.newProxyInstance(person.getClass().getClassLoader(),
person.getClass().getInterfaces(), this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeWork();
Object object = method.invoke(person,args);
afterWork();
return object;
}

private void beforeWork() {
System.out.println("帮客户签合同");
System.out.println("发布公告");
}

private void afterWork() {
System.out.println("抽奖");
System.out.println("开淘宝店");
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
public class ProxyTest {
public static void main(String[] args) {
DynamicProxy dynamicProxy = new DynamicProxy(new GameStreamer());
Streamer streamer = (Streamer) dynamicProxy.getNewInstance();
streamer.work();
System.out.println("---------------------------");
dynamicProxy = new DynamicProxy(new BeautyBigV());
WeiboBigV weiboBigV = (WeiboBigV) dynamicProxy.getNewInstance();
weiboBigV.post();
}
}

实现结果

1
2
3
4
5
6
7
8
9
10
11
帮客户签合同
发布公告
直播打游戏
抽奖
开淘宝店
---------------------------
帮客户签合同
发布公告
上传美照
抽奖
开淘宝店

cglib动态代理

cglib动态代理和JDK动态代理最大区别就是不用定义接口。

需要手动导入cglib-nodep-xxx.jar

定义两个类,不用实现相应接口

1
2
3
4
5
6
7
8
9
10
11
class AnotherGameStreamer{
public void work(){
System.out.println("不用实现接口就可以直播打游戏");
}
}

class AnotherBeautyBigV {
public void post(){
System.out.println("不用实现接口就可以上传美照");
}
}

实现MethodInterceptor接口

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
class CglibProxy implements MethodInterceptor {

private Enhancer enhancer = new Enhancer();

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
beforeWork();
Object object = methodProxy.invokeSuper(o, objects);
afterWork();
return object;
}

private void beforeWork() {
System.out.println("帮客户签合同");
System.out.println("发布公告");
}

private void afterWork() {
System.out.println("抽奖");
System.out.println("开淘宝店");
}

//返回代理对象
public Object getNewInstance(Class c) {
enhancer.setSuperclass(c);
enhancer.setCallback(this);
return enhancer.create();
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ProxyTest {
public static void main(String[] args) {

CglibProxy cglibProxy = new CglibProxy();
AnotherGameStreamer anotherGameStreamer = (AnotherGameStreamer)
cglibProxy.getNewInstance(AnotherGameStreamer.class);
anotherGameStreamer.work();
System.out.println("------------------------------");
AnotherBeautyBigV anotherBeautyBigV = (AnotherBeautyBigV)
cglibProxy.getNewInstance(AnotherBeautyBigV.class);
anotherBeautyBigV.post();

}
}

实现结果

1
2
3
4
5
6
7
8
9
10
11
帮客户签合同
发布公告
不用实现接口就可以直播打游戏
抽奖
开淘宝店
------------------------------
帮客户签合同
发布公告
不用实现接口就可以上传美照
抽奖
开淘宝店

参考

Java静态代理&动态代理笔记

Java Proxy 和 CGLIB 动态代理原理