满足以下三个条件才能称之为代理模式:
1.要有两个角色,代理人与被代理人。
2.对于被代理人来说,这件事一定要做,但是自己做不了,就找代理来做。
3.代理人需要或许被代理人的资料(引用)。
生活中有很多事例都是代理模式,例如找黄牛买票,找中介租房子,明星经纪人,找媒婆介绍媳妇等等都需要有两个角色并且代理人都需要获取到被代理人的资料。
代理模式的优缺点:
优点:
1、职责清晰。
2、高扩展性。
3、智能化。
缺点:
1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
代理模式公有两种,分别是静态代理、动态代理,下面让我利用java代码举一个找中介租房子的小例子。
静态代理:
静态代理需要代理人和被代理人都实现相同的接口,代理人持有被代理人的引用。
第一步定义一个Person借口 定义一个租房子的方法
package proxy.staticProxy; /** * 首先定义一个person的接口 */ public interface Person { //定义一个租房子的方法 public void rentHouse(); }第二步定义一个agent中介实现了person的实现类
package proxy.staticProxy; /** * 创建一个agent代理人实现person接口 * Created by Administrator on 2017/10/19. */ public class Agent implements Person{ //持有被代理人张三的引用 private Zhangsan zhangsan; //使用构造方法注入被代理人对象 public Agent(Zhangsan zhangsan) { this.zhangsan = zhangsan; } public void rentHouse() { //调用被代理人的租房子方法 zhangsan.rentHouse(); } }第三步定义一个zhangsan类实现了person接口
package proxy.staticProxy; /** * 定义一个张三要租房子实现person接口 * Created by Administrator on 2017/10/19. */ public class Zhangsan implements Person { public void rentHouse() { System.out.println("张三租房子"); } }第四部 定义一个测试类测试静态代理
public static void main(String[] args) { //测试类 Person agent = new Agent(new Zhangsan()); agent.rentHouse(); }结果是:
动态代理有java proxy和CGlib两种实现方式,下面我用一个java小例子来说明:
java proxy动态代理:
第一步定义一个person接口
package proxy.javaproxy;
/** * 定义一个person接口 定义一个租房子方法 */ public interface Person { public void rentHouse(); }第二步定义一个zhangsan类 来实现person接口
package proxy.javaproxy; /** * 定义一个zhangsan来 实现person接口 */ public class Zhangsan implements Person{ public void rentHouse(){ System.out.println("张三租房子"); } }
第三步定义动态代理类agent实现InvocationHandler接口并实现invoke方法
package proxy.javaproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 定义动态代理类 实现InvocationHandler接口 */ public class Agent implements InvocationHandler {
//持有被代理人的引用
private Person person; //使用java proxy为被代理人创建一个代理类 public Object getInstance(Person person){ this.person = person; Class clazz = person.getClass(); return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this); } //执行invoke方法 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("中介开始找房子");
//实现被代理人的方法
method.invoke(this.person,args); System.out.println("找房子结束"); return null; }}
第四步创建一个测试类
public static void main(String[] args) { Person d = (Person)new Agent().getInstance(new Zhangsan()); d.rentHouse(); }结果是:
CGlib动态代理:
CGlib动态代理不再需要创建接口,只需代理类实现CGlib包中的MethodInterceptor接口即可
第一步创建代理类Agent实现MethodInterceptor接口并实现intercept接口
第二步创建被代理类public class Agent implements MethodInterceptor { public Object getInstance(Class clazz){ //生成enhancer对象 Enhancer enhancer = new Enhancer(); //生成父类对象 告诉cglib子类需要继承谁 enhancer.setSuperclass(clazz); //回调方法 enhancer.setCallback(this); //1.生成源码 //2.编译成class文件 //3.加载到JVM中,并返回被代理的对象 return enhancer.create(); } public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("中介开始找房子:"); //这个obj的引用是由CGLib给我们new出来的 //cglib new出来以后的对象,是被代理对象的子类(继承了我们自己写的那个类) //OOP, 在new子类之前,实际上默认先调用了我们super()方法的, //new了子类的同时,必须先new出来父类,这就相当于是间接的持有了我们父类的引用 //子类重写了父类的所有的方法 //我们改变子类对象的某些属性,是可以间接的操作父类的属性的 methodProxy.invokeSuper(o,objects); System.out.println("找房子结束"); return null; } }
public class Zhangsan { public void rentHouse(){ System.out.println("租好房子住"); } }
第三步创建测试类
public static void main(String[] args) { //JDK的动态代理是通过接口来进行强制转换的 //生成以后的代理对象,可以强制转换为接口 //CGLib的动态代理是通过生成一个被代理对象的子类,然后重写父类的方法 //生成以后的对象,可以强制转换为被代理对象(也就是用自己写的类) //子类引用赋值给父类 Zhangsan d = (Zhangsan)new Agent().getInstance(Zhangsan.class); d.rentHouse(); }以上就是java代理的三种实现方式