定义:为其他对象提供一种代理以控制对这个对象的访问。代理对象起到中介作用,可去掉功能服务或增加额外的服务(火车票代售处)。
远程代理(客户端服务器模式)
虚拟代理(网站图片延迟加载)
保护代理(控制用户的访问权限)
智能引用代理(火车票代售处)
静态代理
定义:代理和被代理对象在代理之前是确定的,它们都实现相同的接口或者继承相同的抽象类。
1. 没用代理模式之前
1 package com.sakura.proxy; 2 3 /** 4 * Created by sakura on 2018/3/21. 5 */ 6 public interface Moveable { 7 void move(); 8 }
1 package com.sakura.proxy; 2 3 import java.util.Random; 4 5 /** 6 * Created by sakura on 2018/3/21. 7 */ 8 public class Car implements Moveable{ 9 @Override 10 public void move() { 11 long start=System.currentTimeMillis(); 12 System.out.println("汽车开始行驶..."); 13 //实现开车 14 try { 15 Thread.sleep(new Random().nextInt(1000)); 16 System.out.println("汽车行驶中..."); 17 } catch (InterruptedException e) { 18 e.printStackTrace(); 19 } 20 long end=System.currentTimeMillis(); 21 System.out.println("汽车结束行驶...汽车行驶时间:"+(end-start)+"毫秒!"); 22 } 23 }
1 package com.sakura.proxy; 2 3 /** 4 * Created by sakura on 2018/3/21. 5 */ 6 public class Client { 7 public static void main(String[] args) { 8 Car car = new Car(); 9 car.move(); 10 } 11 } 12 /* 13 汽车开始行驶... 14 汽车行驶中... 15 汽车结束行驶...汽车行驶时间:482毫秒! 16 */
2. 用了代理模式(继承)之后
1 package com.sakura.proxy; 2 3 /** 4 * Created by sakura on 2018/3/21. 5 */ 6 public interface Moveable { 7 void move(); 8 }
1 package com.sakura.proxy; 2 3 import java.util.Random; 4 5 /** 6 * Created by sakura on 2018/3/21. 7 */ 8 public class Car implements Moveable{ 9 @Override 10 public void move() { 11 //实现开车 12 try { 13 Thread.sleep(new Random().nextInt(1000)); 14 System.out.println("汽车行驶中..."); 15 } catch (InterruptedException e) { 16 e.printStackTrace(); 17 } 18 } 19 }
1 package com.sakura.proxy; 2 3 /** 4 * Created by sakura on 2018/3/21. 5 */ 6 public class Car2 extends Car { 7 @Override 8 public void move(){ 9 long start=System.currentTimeMillis(); 10 System.out.println("汽车开始行驶..."); 11 super.move(); 12 long end=System.currentTimeMillis(); 13 System.out.println("汽车结束行驶...汽车行驶时间:"+(end-start)+"毫秒!"); 14 } 15 }
1 package com.sakura.proxy; 2 3 /** 4 * Created by sakura on 2018/3/21. 5 */ 6 public class Client { 7 public static void main(String[] args) { 8 Moveable m=new Car2(); 9 m.move(); 10 } 11 } 12 /* 13 汽车开始行驶... 14 汽车行驶中... 15 汽车结束行驶...汽车行驶时间:795毫秒! 16 */
3. 用了代理模式(组合)之后
1 package com.sakura.proxy; 2 3 /** 4 * Created by sakura on 2018/3/21. 5 */ 6 public interface Moveable { 7 void move(); 8 }
1 package com.sakura.proxy; 2 3 import java.util.Random; 4 5 /** 6 * Created by sakura on 2018/3/21. 7 */ 8 public class Car implements Moveable{ 9 @Override 10 public void move() { 11 //实现开车 12 try { 13 Thread.sleep(new Random().nextInt(1000)); 14 System.out.println("汽车行驶中..."); 15 } catch (InterruptedException e) { 16 e.printStackTrace(); 17 } 18 } 19 }
1 package com.sakura.proxy; 2 3 /** 4 * Created by sakura on 2018/3/21. 5 */ 6 public class Car2 implements Moveable { 7 public Car2(Car car){ 8 super(); 9 this.car=car; 10 } 11 private Car car; 12 13 @Override 14 public void move() { 15 long start=System.currentTimeMillis(); 16 System.out.println("汽车开始行驶..."); 17 car.move(); 18 long end=System.currentTimeMillis(); 19 System.out.println("汽车结束行驶...汽车行驶时间:"+(end-start)+"毫秒!"); 20 } 21 }
1 package com.sakura.proxy; 2 3 /** 4 * Created by sakura on 2018/3/21. 5 */ 6 public class Client { 7 public static void main(String[] args) { 8 Car car=new Car(); 9 Moveable m=new Car2(car); 10 m.move(); 11 } 12 } 13 /* 14 汽车开始行驶... 15 汽车行驶中... 16 汽车结束行驶...汽车行驶时间:360毫秒! 17 */
相比继承方式而言,组合方式扩展性更好。
加上日志功能:
1 package com.sakura.proxy; 2 3 /** 4 * Created by sakura on 2018/3/21. 5 */ 6 public interface Moveable { 7 void move(); 8 }
1 package com.sakura.proxy; 2 3 import java.util.Random; 4 5 /** 6 * Created by sakura on 2018/3/21. 7 */ 8 public class Car implements Moveable{ 9 @Override 10 public void move() { 11 //实现开车 12 try { 13 Thread.sleep(new Random().nextInt(1000)); 14 System.out.println("汽车行驶中..."); 15 } catch (InterruptedException e) { 16 e.printStackTrace(); 17 } 18 } 19 }
1 package com.sakura.proxy; 2 3 /** 4 * Created by sakura on 2018/3/21. 5 */ 6 public class CarTimeProxy implements Moveable { 7 public CarTimeProxy(Moveable m){ 8 super(); 9 this.m=m; 10 } 11 private Moveable m; 12 @Override 13 public void move() { 14 long start=System.currentTimeMillis(); 15 System.out.println("汽车开始行驶..."); 16 m.move(); 17 long end=System.currentTimeMillis(); 18 System.out.println("汽车结束行驶...汽车行驶时间:"+(end-start)+"毫秒!"); 19 } 20 }
1 package com.sakura.proxy; 2 3 /** 4 * Created by sakura on 2018/3/21. 5 */ 6 public class CarLogProxy implements Moveable { 7 public CarLogProxy(Moveable m){ 8 super(); 9 this.m=m; 10 } 11 private Moveable m; 12 @Override 13 public void move() { 14 System.out.println("日志开始..."); 15 m.move(); 16 System.out.println("日志结束..."); 17 } 18 }
1 package com.sakura.proxy; 2 3 /** 4 * Created by sakura on 2018/3/21. 5 */ 6 public class Client { 7 public static void main(String[] args) { 8 Car car=new Car(); 9 CarTimeProxy ctp=new CarTimeProxy(car); 10 CarLogProxy clp=new CarLogProxy(ctp); 11 clp.move(); 12 } 13 } 14 /* 15 日志开始... 16 汽车开始行驶... 17 汽车行驶中... 18 汽车结束行驶...汽车行驶时间:228毫秒! 19 日志结束... 20 */
但是问题来了,如果这会汽车变成火车了,难道又要重写一个TrainTimeProxy和TrainLogProxy吗,能不能只写一个TimeProxy和LogProxy实现对各种车的代理呢?
动态代理
1. JDK动态代理
只能代理实现了接口的类,没有实现接口的类不能实现JDK的动态代理。
动态代理实现步骤:
创建一个实现接口InvocationHandler的类,它必须实现invoke方法
创建被代理的类以及接口
调用Proxy的静态方法,创建一个代理类newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
通过代理调用方法
1 package com.sakura.proxy; 2 3 /** 4 * Created by sakura on 2018/3/21. 5 */ 6 public interface Moveable { 7 void move(); 8 }
1 package com.sakura.proxy; 2 3 import java.util.Random; 4 5 /** 6 * Created by sakura on 2018/3/21. 7 */ 8 public class Car implements Moveable{ 9 @Override 10 public void move() { 11 //实现开车 12 try { 13 Thread.sleep(new Random().nextInt(1000)); 14 System.out.println("汽车行驶中..."); 15 } catch (InterruptedException e) { 16 e.printStackTrace(); 17 } 18 } 19 }
1 package com.sakura.proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 /** 7 * Created by sakura on 2018/3/21. 8 */ 9 public class TimeHandler implements InvocationHandler { 10 private Object target; 11 public TimeHandler(Object target){ 12 super(); 13 this.target=target; 14 } 15 @Override 16 //proxy:代理类 method:被代理的方法 args:方法的参数数组 17 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 18 long start=System.currentTimeMillis(); 19 System.out.println("汽车开始行驶..."); 20 method.invoke(target); 21 long end=System.currentTimeMillis(); 22 System.out.println("汽车结束行驶...汽车行驶时间:"+(end-start)+"毫秒!"); 23 return null; 24 } 25 }
1 package com.sakura.proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Proxy; 5 6 /** 7 * Created by sakura on 2018/3/21. 8 */ 9 public class Test { 10 public static void main(String[] args) { 11 Car car=new Car(); 12 InvocationHandler h= new TimeHandler(car); 13 Class<?> cls=car.getClass(); 14 //loader:类加载器 interfaces:实现接口 h:InvocationHandler 15 Moveable m= (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h); 16 m.move(); 17 } 18 } 19 /* 20 汽车开始行驶... 21 汽车行驶中... 22 汽车结束行驶...汽车行驶时间:171毫秒! 23 */
2. cglib动态代理
针对类来实现代理的,对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用(继承实现,不能代理被final修饰的类)。
需要导入一个名为cglib-nodep-2.2.jar的包。