代理模式
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式可以分为两种,一种是静态代理,一种是动态代理。
静态代理采用的方式就是我们手动的将这些行为换进去,然后让编译器帮我们编译,同时也就将字节码在原有类的基础上加入一些其他的东西或者替换原有的东西,产生一个新的与原有类接口相同却行为不同的类型。我们以歌星、经纪人为例,歌星就是我们要代理的类,经纪人就是代理类,我们要找歌星让他唱歌,要先找到他的经纪人,同时要求歌星和经纪人实现同一个sing的接口。demo如下:
package com.example.demo.Proxy; public interface Skills{ void sing(); }
package com.example.demo.Proxy; public class Star implements Skills{ private String name; public Star(String name) { this.name = name; } public Star() { } @Override public void sing() { System.out.println(name + "唱歌"); } }
package com.example.demo.Proxy; public class Broker implements Skills{ private Skills tatget; public Broker(Skills tatget) { this.tatget = tatget; } @Override public void sing() { tatget.sing(); } }
Client端调用如下:
public static void main(String[] args) { Skills proxy = new Broker(new Star("liying")); proxy.sing(); }
如果纯从代码角度看,静态代理和装饰模式没有什么区别,但是从使用意义上来看,代理模式注重对对象某一功能的流程把控和辅助。它可以控制对象做某些事,重心是为了借用对象的功能完成某一流程,而非对象功能如何;装饰模式注重对对象功能的扩展,它不关心外界如何调用,只注重对对象功能的加强,装饰后还是对象本身。所以,对于代理类,如何调用对象的某一功能是思考重点,而不需要兼顾对象的所有功能;对于装饰类,如何扩展对象的某一功能是思考重点,同时也需要兼顾对象的其它功能,因为再怎么装饰,本质也是对象本身,要担负起对象应有的职责。
静态代理对于这种,被代理的对象很固定,我们只需要去代理一个类或者若干固定的类,数量不是太多的时候,可以使用,而且其实效果比动态代理更好,因为动态代理就是在运行期间动态生成代理类,所以需要消耗的时间会更久一点。但如果我们需要代理很多的类,例如spring项目添加事务,要生成很多的代理类,这个时候如果静态代理则项目会出现很多重复代码,变得臃肿不优雅,所以spring采取了动态代理。动态代理又有两种实现:jdk动态代理(要求被代理类必须实现某个接口)和cglib动态代理(采用继承方式,生成 的代理类实际上是目标类的子类),spring采用的方式是如果目标类有接口实现则使用jdk动态代理,否则则使用cglib代理。下面给出两种代理方式的实现。
jdk动态代理
package com.example.demo.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxy implements InvocationHandler{ private Skills skills; public DynamicProxy(Skills skills) { this.skills = skills; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("执行前"); Object ob = method.invoke(skills,args); System.out.println("执行后"); return ob; } public Object getProxy(){ return Proxy.newProxyInstance(getClass().getClassLoader(),skills.getClass().getInterfaces(),this); } }
cglib动态代理
package com.example.demo.Proxy; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * Created by Administrator on 2018/12/28. */ public class CglibFactory { static <T> Object getProxy(T t){ Enhancer enhancer = new Enhancer();//帮组生成代理类 enhancer.setSuperclass(t.getClass());//设置目标类 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("执行前"); Object result = method.invoke(t,objects); System.out.println("执行后"); return result; } }); Object proxyObj = enhancer.create();//生成代理对象 return proxyObj; } }
Client端代码
public class Client { // public static void main(String[] args) { // DynamicProxy d = new DynamicProxy(new Star("huge")); // Skills proxy = (Skills) d.getProxy(); // proxy.sing(); // } public static void main(String[] args) { Skills s = (Skills) CglibFactory.getProxy(new Star("HUGE")); s.sing(); } }