代理模式属于结构型模式java
定义:代理模式为其余对象提供一种代理以控制对这个对象的访问。编程
代理模式是java框架层面应用最普遍的少数几种设计模式之一,很是重要。设计模式
适用场景:安全
远程代理,为一个对象在不一样的地址空间提供局部表明,这样能够隐藏一个对象存在于不一样地址空间的事实。性能优化
虚拟代理,根据须要建立开销很大的对象,经过它来存放实例化须要很长时间的对象,这样能够达到性能优化;框架
安全代理,用来控制真实对象访问时的权限。通常用于对象应该有不一样的访问权限的时候;ide
智能指引,是指当调用真实的对象的时候,代理处理另外的一些事情(用的比较多)性能
代理模式要求代理实现与被代理对象相同的接口(cglib与被代理对象是子类与父类的关系),以保证任什么时候候都能代替真实对象。这也是它与适配器模式的区别!!测试
代理模式普遍应用于aop编程。可以在不改变源代码的前提下提供统一的日志管理,先后置拦截器,符合开放封闭原则、依赖倒置原则,优化
下面代码属于静态代理,大体场景是追求者会追妹子,但他不认识某girl,而经过代理类认识,因此追求者经过代理类对妹子展开了追求。
public class ProxyTest { public static void main(String[] args) { PursuitWay pursuitWay=new Proxy(new Pursuiter(new Girl("小白"))); pursuitWay.giveFlower(); pursuitWay.giveGift(); } } interface PursuitWay{ void giveFlower(); void giveGift(); } class Girl{ private String name; public Girl(String name) { this.name=name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Pursuiter implements PursuitWay{ Girl girl; public Pursuiter(Girl girl){ this.girl=girl; } @Override public void giveFlower() { System.out.println("追求者送"+girl.getName()+"花"); } @Override public void giveGift() { System.out.println("追求者送"+girl.getName()+"礼物"); } } class Proxy implements PursuitWay{ PursuitWay pursuter; public Proxy(PursuitWay pursuiter){ this.pursuter=pursuiter; } @Override public void giveFlower() { pursuter.giveFlower(); } @Override public void giveGift() { pursuter.giveGift(); } }
既然是经过代理去追妹子,那每次苦力活代理作作日志,设置个障碍就不难理解了吧。
上述功能若是要经过适配器模式实现,则proxy没必要非要实现PursuitWay,它会有本身的方法而没必要非要是giveXXX,只须要在它本身的方法中实现pursuter的giveXXX方法就能够了,具体代码略。
上述代理模式属于静态代理,由于代理类是咱们本身编写出来的,而动态代理则是经过java虚拟机,在运行期间生成的字节码。
下述代码是经过动态代理实现的相同功能
1. 获取追求者上的全部接口列表;
2. 肯定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX ;
3. 根据须要实现的接口信息,在代码中动态建立 该Proxy类的字节码;
4 . 将对应的字节码转换为对应的class 对象;
5. 建立InvocationHandler 实例handler,用来处理Proxy全部方法调用;
6. Proxy 的class对象 以建立的handler对象为参数,实例化一个proxy对象
public class ProxyTest { public static void main(String[] args) { Class clazz=Proxy.getProxyClass(Pursuiter.class.getClassLoader(), Pursuiter.class.getInterfaces()); System.out.println("proxy类为"+clazz.getName()); System.out.println("proxy实现的接口有"+clazz.getInterfaces()[0].getName()); System.out.println("-----开始生成代理对象(实际上该代理对象就是一个该接口的实现类)"); PursuitWay pursuter=(PursuitWay) Proxy.newProxyInstance(Pursuiter.class.getClassLoader(), Pursuiter.class.getInterfaces(), new MyInvocationHandler(new Pursuiter(new Girl("小白")))); pursuter.giveFlower(); pursuter.giveGift(); } } interface PursuitWay{ void giveFlower(); void giveGift(); } class Girl{ private String name; public Girl(String name) { this.name=name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Pursuiter implements PursuitWay{ Girl girl; public Pursuiter(Girl girl){ this.girl=girl; } @Override public void giveFlower() { System.out.println("追求者送"+girl.getName()+"花"); } @Override public void giveGift() { System.out.println("追求者送"+girl.getName()+"礼物"); } } class MyInvocationHandler implements InvocationHandler{ Object object; public MyInvocationHandler(Object object){ this.object=object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(object, args); } }
上述代码经过jdk自带的代理类实现,它和静态代理类有一样的局限性,就是要求被代理类必须有一个或者多个对应具体业务逻辑的接口。myInvocationHandler里边的invoke方法中能够提供拦截、写日志等功能。
cglib包的代理类CglibProxy是针对某个类生成一个子类,该子类天然会包括其父类的全部业务逻辑方法。并且不在局限于必须有上层接口。可是cglib包也要求被代理类不能为final类,不然继承不了,测试代码和动态代理很像,略。
cglib底层采用ASM字节码生成框架,使用字节码技术生成代理类,理论上比使用Java反射效率要高,不过有大神曾经测试过,貌似性能差很少,并且jdk的动态代理还要比cglib效率高一点点。有兴趣的朋友能够去试试。
欢迎大神交流意见。
下一节将会讲解工厂方法模式,该模式在service层应用很广泛。敬请期待。