定义 :
为其他对象提供一种代理以控制对这个对象的访问
应用实例 :
1.windows里面的快捷方式 2.猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和 孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高 翠兰代理类。3.买火车票票不一定在火车站买,也可以去代售点4.一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账 号上资金的控制。 5.spring aop [详解](https://www.cnblogs.com/hongwz/p/5764917.html)
代理模式有几种: 虚拟代理,计数代理,远程代理,动态代理。主要分为两类, 静态代理和动态代理 。静态代理比较简单,是由程序员编写的代理类,并在程序运行前就编译好的,而不是由程序动态产生代理类,这就是所谓的静态。
静态代理:
/** * 卖票接口 * * @author Administrator * */public interface Ticket { void sellTicket();}/** * 火车站类 购票、改签、退票、 * * @author Administrator * */public class Trainstation implements Ticket { @Override public void sellTicket() { System.out.println("火车站售票~~~"); } /** * 改签 */ @SuppressWarnings("unused") private void changeTicket() { System.out.println("改签~"); } /** * 退票 */ @SuppressWarnings("unused") private void backTicket() { System.err.println("退票~"); }}/** * 黄牛代理 * * @author Administrator * */public class CattleProxy implements Ticket { private Ticket ticket; public CattleProxy(Ticket ticket) { this.ticket = ticket; } @Override public void sellTicket() { // TODO Auto-generated method stub System.err.println("黄牛卖票"); }}public class ProxyTest { public static void main(String[] args) { // TODO Auto-generated method stub Trainstation trainstation = new Trainstation(); CattleProxy cattleProxy = new CattleProxy(trainstation); cattleProxy.sellTicket(); }
UML图
静态代理实现中,一个委托类对应一个代理类,代理类在编译期间就已经确定。
动态代理
动态代理中,代理类并不是在Java代码中实现,而是在运行时期生成,相比静态代理,动态代理可以很方便的对委托类的方法进行统一处理,如添加方法调用次数、添加日志功能等等,动态代理分为jdk动态代理和cglib动态代理,下面通过一个例子看看如何实现jdk动态代理。
1、定义业务逻辑
public interface Service { //目标方法 public abstract void add(); } public class UserServiceImpl implements Service { public void add() { System.out.println("This is add service"); } }
2、利用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口定义代理类的实现。
class MyInvocatioHandler implements InvocationHandler { private Object target; public MyInvocatioHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("-----before-----"); Object result = method.invoke(target, args); System.out.println("-----end-----"); return result; } // 生成代理对象 public Object getProxy() { ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class<?>[] interfaces = target.getClass().getInterfaces(); return Proxy.newProxyInstance(loader, interfaces, this); }}
3、使用动态代理
public class ProxyTest { public static void main(String[] args) { Service service = new UserServiceImpl(); MyInvocatioHandler handler = new MyInvocatioHandler(service); Service serviceProxy = (Service)handler.getProxy(); serviceProxy.add(); }}
执行结果:
-----before----- This is add service -----end----- 代理对象的生成过程由Proxy类的newProxyInstance方法实现,分为3个步骤: 1、ProxyGenerator.generateProxyClass方法负责生成代理类的字节码,生成逻辑比较复杂,有兴趣的同学可以继续分析源码 sun.misc.ProxyGenerator;
// proxyName:格式如 "com.sun.proxy.$Proxy.1"; // interfaces:代理类需要实现的接口数组; // accessFlags:代理类的访问标识; byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags); 2、native方法Proxy.defineClass0负责字节码加载的实现,并返回对应的Class对象。
Class clazz = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); 3、利用clazz.newInstance反射机制生成代理类的对象;
优点:
职责清晰
2.高扩展性
3.智能化
缺点:
1.由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
2 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
使用场景:
按职责来划分,通常有一下使用场景:
1.远程代理 也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实
2.虚拟代理 根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象
3.Copy-on-Write代理
4.保护(Protect or Access)代理
5.Cache代理
6.防火墙(Firewall)代理
7.同步化(Synchronization)代理
7.智能引用(Smart Reference)代理
注意事项:
1.和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理迷失不能改变所代理类的接口
2.和装饰模式的区别:装饰模式为了增强功能,而代理模式是为了加以控制
联系客服