三流码奴的自我救赎

0%

Java动态代理

代理模式

说动态代理肯定就得先弄明白什么是代理模式。

现在思考这样一个场景:

买一台电脑,直接去官网买是原价,去并夕夕买可以便宜500同时积分,请问你是选择官网还是并夕夕?

在这个场景中,官网就是被代理类,并夕夕就是代理类,代理的行为是卖电脑,可以看出经过了并夕夕的代理同样的商品变得更便宜了。在这个买卖过程中,用户并不需要关心电脑是如何打折的,只是花了钱同时达到了目的。这就是代理模式的应用场景:

代理模式可以在完成主要任务的同时完成一些前置或后置的工作,这个过程对用户透明,用户只需要关心主要任务

代理模式在很多中场景下都发挥了很大的作用,比如Windows中的快捷方式就是一个代理模式的应用,通过将启动程序的操作代理给快捷方式,可以在启动时直接加载快捷方式带有的参数。

两种代理实现方式

代理模式一般分为静态代理动态代理

举个例子,我们现在有一个工作叫卖电脑:

1
2
3
interface Work {
public void sellComputer();
}

官网要卖电脑要实现这个接口:

1
2
3
4
5
6
class Official implements {
@Override
public void sellComputer() {
System.out.println("official sells");
}
}

静态代理

所谓静态代理就是在编译之前直接把代理类实现好,在运行过程中是固定的代理实现,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 静态代理类
class Pdd implements {
private Work official;

public Pdd (Work official) {
this.official = official;
}

@Override
public void sellComputer() {
// 代理类做前置工作
discount();
// 在这里真正执行卖电脑的方法
official.sellComputer();
}

private void discount() {
System.out.println("打折!");
}
}

静态代理的缺点还是很明显的:

如果有n个类需要被代理,那么至少需要写n个静态代理类。当业务复杂到一定程度的时候,这会给开发和维护带来很高的成本。

动态代理

既然静态代理是写死的代理类实现,那么动态代理类就是在运行过程中决定需要对哪个类进行代理的代理类:

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
public class ProxyHandler implements InvocationHandler {
private Object target;

public Object bind(Object tar) {
this.target = target;
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}

public Object invoke(Object proxy , Method method , Object[] args)throws Throwable {
Object result = null;
// 在这里真正调用被代理类的方法,在执行这行代码的前后可以执行代理类的额外功能
result = method.invoke(target,args);
// 打折
return discount(result);
}

private void discount() {
System.out.println("打折!");
}
}

public class TestProxy {
public static void main(String args[])
{
ProxyHandler proxy = new ProxyHandler();
// 在这里绑定真正调用的实例
// 可以发现在这里通过接口Work将被代理类和代理类联系起来
// 通过InvocationHandler接口定义的invoke方法,在该对象执行对应方法的时候调用被代理类对应的方法
Work work = (Work) proxy.bind(new Official());
work.sellComputer();
}
}

可以看出,动态代理可以在对具有统一行为的类进行代理的同时有效的减少代理类的数量。

其实动态代理还有一种使用方式,通过动态代理,可以在没有实现类的情况下创建接口的实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("sellComputer")) {
System.out.println("computer sold");
}
return null;
}
};

Work work = (Work) Proxy.newProxyInstance(
Work.class.getClassLoader(), // 传入ClassLoader
new Class[] { Work.class }, // 传入要实现的接口
handler); // 传入处理调用方法的InvocationHandler
work.sellComputer();