- 动态代理的好处
上一篇简单说了说静态代理, 代理模式的优点不言而喻, 不但对真实对象的保护帮了大忙, 还间接地解决了类与类之间的高耦合, 但是静态代理还是有它的缺陷, 仔细看过上一篇的同学应该发现了, 我们的代理类只能代理实现了同一接口的类, 就好比一匹骏马被永远的拴在了树上, 失去了它本该有的价值。 为了解决这一缺陷, 动态代理模式应运而生。
- 目前常用的动态代理技术
在java中有多种动态代理技术, 比如JDK, CGLIB, Javassist, ASM, 其中最常用的有两种, 一种是JDK动态代理, 这是JDK自带的功能; 另一种是CGLIB, 这是第三方提供的一个技术。目前Spring常用JDK 和 CGLIB, 而Mybatis 还使用了Javassist, 但无论是那种动态代理, 理念都很相似, 都是利用反射等机制来实现。
- 代码实现
包结构如下图
Negotiation.java
package proxy.dynamic;
// 谈判接口
public interface Negotiation {
// 谈工资
void money();
}
Programmer.java
package proxy.dynamic;
// 码农
public class Programmer implements Negotiation {
@Override
public void money() {
System.out.println("No, I need 15000$"); // 码农需要 15000$
}
}
Client.java
package proxy.dynamic;
// 客户
public class Client implements Negotiation {
@Override
public void money() {
System.out.println("I will pay you 10000$");
}
}
Agent.java
package proxy.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Agent implements InvocationHandler {
private Object target = null; // 真实对象
/**
* 建立真实对象与代理对象之间的关系
* @param target 真实对象
* @return 代理对象
*/
public Object bind(Object target)
{
this.target = target;
// newProxyInstance() 包含三个参数: 1.类加载器 2.动态代理对象的继承接口 3.实现方法逻辑的代理类
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),
this.target.getClass().getInterfaces(),
this);
}
/**
*
* @param proxy 代理对象
* @param method 当前调度的方法
* @param args 当前方法的参数
* @return 代理结果返回
* @throws Throwable 异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("\n进入代理逻辑..");
System.out.println("在调度代理对象之前的服务...");
Object result = method.invoke(this.target, args); // 相当于调用 money() 方法
System.out.println("在调度代理对象之后的服务...");
return result;
}
}
Test.java
package proxy.dynamic;
public class Test {
public static void main(String[] args)
{
Agent agent = new Agent(); // 中间商
Client client = new Client(); // 客户
Programmer programmer = new Programmer(); // 码农
Negotiation clientAgent = (Negotiation) agent.bind(client); // 注意此时客户已经被代理
clientAgent.money();
Negotiation programmerAgent = (Negotiation) agent.bind(programmer); // 注意此时码农已经被代理
programmerAgent.money();
}
}
首先通过bind方法绑定了代理关系, 然后在代理对象调度 mony方法时进入了代理逻辑.
- 结果
88~