1. 代理模式的引入
王大爷借了小李1.5亿,小赖是个无赖横竖就是不还钱,王大爷身子弱讨不回钱就请了讨债公司的小强,最后小强通过一系列**(过于残暴被打码了)的手段帮助王大爷讨回欠款。完事后还帮王大爷做了封口的工作。这个场景中,小强就是一个代理的存在。
2. 静态代理模式的实现
package test;
public class TsetProxy {
public static void main(String[] args) {
ProxySubject proxySubject = new ProxySubject(new RealSubjest());
proxySubject.getDebt();
}
}
interface Subject{
public void getDebt();//讨债
}
class RealSubjest implements Subject{
@Override
public void getDebt() {
// 王大爷讨债
System.out.println("王大爷讨回1.5亿欠款");
}
}
//代理讨债
class ProxySubject implements Subject{
private Subject realSubject ;
public ProxySubject(Subject subject) {
this.realSubject = subject;
}
public void prepare() {
System.out.println("讨债前的准备工作...威胁、恐吓、外加毒打一顿....");
}
@Override
public void getDebt() {
this.prepare();
this.realSubject.getDebt();
this.destory();
}
public void destory() {
System.out.println("讨债后的清理工作....杀人灭口、毁尸灭迹......");
}
}
剧情的发展好像有点脱离控制了。为什么讨完债要杀人灭口,毁尸灭迹呢?这不是重点。
重点是!!!
代理类调用了核心类的接口对象,完成了核心类的方法。其实上面的过程就像一个“汉堡包”,现在看来可能比较像“三明治”。看到后面,你会发现代理模式其实是一个“汉堡包”。
3. 静态代理模式的优化
上面的代码虽然简单,但是分层结构不清晰,改进如下:
package Service;
public interface IDebtService {
public void getDebt() ;
}
package Service;
public class DebtServiceImpl implements IDebtService{
@Override
public void getDebt() {
System.out.println("王大爷讨回1.5亿欠款.......");
}
}
package Manager;
public interface IDebtManager {
//讨债前准备工作
public void brefore();
//讨债后清理工作
public void after();
}
package Manager;
public class DebtManagerImpl implements IDebtManager{
@Override
public void brefore() {
System.out.println("讨债前的准备工作:威胁、恐吓、外加毒打一顿....");
}
@Override
public void after() {
System.out.println("讨债后的清理工作:杀人灭口、毁尸灭迹......");
}
}
package Proxy;
import Manager.IDebtManager;
import Service.IDebtService;
public class DebtStaticProxyImpl implements IDebtService{
private IDebtManager proxy; //代理对象
private IDebtService target; //核心对象
public DebtStaticProxyImpl(IDebtManager proxy, IDebtService target) {
this.proxy = proxy;
this.target = target;
}
@Override
public void getDebt() {
proxy.brefore(); //前期工作
target.getDebt(); //讨债过程
proxy.after(); //后期工作
}
}
测试类:
import Manager.DebtManagerImpl;
import Manager.IDebtManager;
import Proxy.DebtStaticProxyImpl;
import Service.DebtServiceImpl;
import Service.IDebtService;
public class Main {
public static void main(String[] args) {
//准备一个王大爷对象
IDebtService target = new DebtServiceImpl();
//准备一个代理对象
IDebtManager proxy = new DebtManagerImpl();
//代理程序
IDebtService debtService = new DebtStaticProxyImpl(proxy, target);
debtService.getDebt();
}
}
运行结果:
讨债前的准备工作:威胁、恐吓、外加毒打一顿....
王大爷讨回1.5亿欠款.......
讨债后的清理工作:杀人灭口、毁尸灭迹......
讨债公司也并没有这么简单,既然帮王大爷讨债,那总不能白讨是吧,这讨债费这么算得事先说得明明白白,事后算得清清楚楚才行。于是来了财务小钱(另一个代理),负责处理这个过程的讨债费用问题。
财务代理类:
package Manager;
public class DebtFeeManagerImpl implements IDebtManager{
@Override
public void brefore() {
System.out.println("讨债前财务工作:拟定讨债费用合同,监督双方签字..........");
}
@Override
public void after() {
System.out.println("讨债后财务工作:清算讨债费用,帮助双方完成讨债费交付..........");
}
}
测试类:
import Manager.DebtFeeManagerImpl;
import Manager.DebtManagerImpl;
import Manager.IDebtManager;
import Proxy.DebtStaticProxyImpl;
import Service.DebtServiceImpl;
import Service.IDebtService;
public class Main {
public static void main(String[] args) {
//准备一个王大爷对象
IDebtService target = new DebtServiceImpl();
//准备一个代理对象
IDebtManager proxy = new DebtManagerImpl();
//准备一个财务代理
IDebtManager proxy2 = new DebtFeeManagerImpl();
//代理程序
IDebtService debtService = new DebtStaticProxyImpl(proxy, target);//讨债
debtService = new DebtStaticProxyImpl(proxy2, debtService);//财务清算
debtService.getDebt();
}
}
运行结果:
讨债前财务工作:拟定讨债费用合同,监督双方签字..........
讨债前的准备工作:威胁、恐吓、外加毒打一顿....
王大爷讨回1.5亿欠款.......
讨债后的清理工作:杀人灭口、毁尸灭迹......
讨债后财务工作:清算讨债费用,帮助双方完成讨债费交付..........
但是现在的程序是有缺点的。第一点是proxy继承了核心类,这就导致了Service层每增加一个接口类,Proxy层就要对应增加一个新的类,但是这些proxy类的完成的事情是一致的,就是将核心类和代理类编织在一起。第二点就是静态代理内部的实现跟Service接口的具体方法耦合在一起了,一旦改动接口的方法名称(当然一般不会这么做),静态代理类也得跟着改。
4. 动态代理的实现
静态代理是在编译时就生成代理对象,而动态代理是运行期才生产代理对象。
动态代理有两种:“JDK动态代理”和“CGLIB动态代理”
4.1 JDK动态代理
关键类:java.lang.reflect.InvocationHandler(编织器)和java.lang.reflect.Proxy
程序实现:在上一个工程的基础上把DebtStaticProxyImpl干掉,然后写一个DynamicProxyHandler类
package Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import Manager.IDebtManager;
public class DynamicProxyHandler implements InvocationHandler{
private Object target; //核心类
private IDebtManager iDebtManager; //代理类
public DynamicProxyHandler(Object target, IDebtManager iDebtManager) {
this.target = target;
this.iDebtManager = iDebtManager;
}
/**
* proxy:代理类
* method:被调用的核心方法
* args:核心方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
iDebtManager.brefore();
Object res = method.invoke(target, args);
iDebtManager.after();
return res;
}
}
测试类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import Manager.DebtManagerImpl;
import Manager.IDebtManager;
import Proxy.DynamicProxyHandler;
import Service.DebtServiceImpl;
import Service.IDebtService;
public class Main {
public static void main(String[] args) {
//准备一个王大爷对象
IDebtService target = new DebtServiceImpl();
//准备一个代理对象
IDebtManager proxy = new DebtManagerImpl();
//准备一个Handler(编织器)
InvocationHandler handler = new DynamicProxyHandler(target, proxy);
//代理程序
IDebtService iDebtService = (IDebtService)Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler);
iDebtService.getDebt();
}
}
4.2 CGLIB动态代理
JDK动态代理有个局限:只适用于面向接口编程。对于没有接口的类,如何实现动态代理呢,这就需要CGLib(Code Generation Library)了。
首先,CGLIB是一个第三方的框架,所以需要引入jar包,官方下载地址:https://github.com/cglib/cglib/releases
CGlibHandler:
package Proxy;
import java.lang.reflect.Method;
import Manager.IDebtManager;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* MethodInterceptor : 方法拦截器
* @author luo
*
*/
public class CGlibHandler implements MethodInterceptor{
private IDebtManager iDebtManager;
public CGlibHandler(IDebtManager iDebtManager) {
this.iDebtManager = iDebtManager;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// TODO Auto-generated method stub
iDebtManager.brefore();
Object res = proxy.invokeSuper(obj, args);
iDebtManager.after();
return res;
}
}
测试类:
import Manager.DebtManagerImpl;
import Manager.IDebtManager;
import Proxy.CGlibHandler;
import Service.DebtServiceImpl;
import Service.IDebtService;
import net.sf.cglib.proxy.Enhancer;
public class Main {
public static void main(String[] args) {
//准备一个王大爷对象
IDebtService target = new DebtServiceImpl();
//准备一个代理对象
IDebtManager proxy = new DebtManagerImpl();
//准备一个Handler(编织器)
CGlibHandler handler = new CGlibHandler(proxy);
//代理程序
Enhancer enhancer = new Enhancer(); //通过cglib生成目标对象的子类来动态创建代理对象
enhancer.setSuperclass(target.getClass());//设置父类
enhancer.setCallback(handler);//设置处理逻辑
IDebtService iDebtService = (IDebtService)enhancer.create();
iDebtService.getDebt();
}
}
4.3 总结
CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。