为其他类提供一种代理,以控制对这个类的访问
代理可以理解为助理,中介等,你想找直接领导只能找中间者,然后通过中间者去找领导
在面向对象系统中,有些对象由于(创建对象开销大、操作安全控制、需要进程外的访问)等一系列的问题,直接访问会带来很多麻烦,所以我们在访问此对象时加上一个此对象的访问层
抽象角色:通过接口或抽象类声明真实角色实现的业务方法
代理角色:实现抽象角色,是真实角色的代理
真实角色:实现抽象角色,定义真是角色需要实现的业务逻辑,供代理角色调用
1、提供移动接口
package com.xjion.noproxy; public interface Moveable { void move(); }2、提供汽车
package com.xjion.noproxy; import java.util.Random; public class Car implements Moveable{ @Override public void move() { System.out.println("汽车开始移动..."); try { long startTime=System.currentTimeMillis(); System.out.println("汽车移动中..."); Thread.sleep(new Random().nextInt(2000)); long endTime=System.currentTimeMillis(); System.out.println("汽车运行结束,消耗时间为:"+(endTime-startTime)+"毫秒数!"); } catch (Exception e) { e.printStackTrace(); } } }3、测试
package com.xjion.noproxy; public class Test { public static void main(String[] args) { Moveable car=new Car(); car.move(); } }1、移动接口
package com.xjion.staticproxy; public interface Moveable { void move(); }2、汽车
package com.xjion.staticproxy; import java.util.Random; public class Car implements Moveable{ @Override public void move() { try { System.out.println("汽车移动中..."); Thread.sleep(new Random().nextInt(2000)); } catch (Exception e) { e.printStackTrace(); } } }3、代理添加日志,计时
package com.xjion.staticproxy; /** * 通过继承的方式实现静态代理 * */ public class LogTimeProxy extends Car{ @Override public void move() { System.out.println("记录开始日志"); System.out.println("汽车开始移动..."); long startTime=System.currentTimeMillis(); super.move(); long endTime=System.currentTimeMillis(); System.out.println("汽车停止移动,移动的时间为:"+(endTime-startTime)+"毫秒!"); System.out.println("记录结束日志"); } }4、测试
package com.xjion.staticproxy; public class Test { public static void main(String[] args) { Moveable car=new LogTimeProxy(); car.move(); } }1、提供移动接口,汽车
同上 ↑
2、提供计时功能
package com.xjion.staticproxy2; public class TimeProxy implements Moveable{ private Moveable moveable; public TimeProxy(Moveable moveable) { this.moveable = moveable; } @Override public void move() { System.out.println("汽车开始移动..."); long startTime=System.currentTimeMillis(); moveable.move(); long endTime=System.currentTimeMillis(); System.out.println("汽车停止移动,移动的时间为:"+(endTime-startTime)+"毫秒!"); } }3、提供日志功能
package com.xjion.staticproxy2; public class LogProxy implements Moveable{ private Moveable moveable; public LogProxy(Moveable moveable) { this.moveable = moveable; } @Override public void move() { System.out.println("记录日志开始..."); moveable.move(); System.out.println("记录日志结束..."); } }4、测试
package com.cdsxt.staticproxy2; public class Test { public static void main(String[] args) { //计时并打印日志 //Moveable car=new TimeProxy(new LogProxy(new Car())); //计时 Moveable car=new TimeProxy(new Car()); car.move(); } }1、汽车和移动同上
2、飞机和飞行接口
package com.xjion.dynamicproxy; public interface Flyable { void fly(); } package com.xjion.dynamicproxy; import java.util.Random; public class Aircraft implements Flyable{ @Override public void fly() { try { System.out.println("飞机在飞飞飞..."); Thread.sleep(new Random().nextInt(2000)); } catch (Exception e) { e.printStackTrace(); } } }3、代理
package com.xjion.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 1)实现InvocationHandler,重写接口的方法 * 2)获取代理对象 Proxy.newProxyInstance调用 */ public class LogProxy implements InvocationHandler{ private Object obj; //给被代理对象赋值 public LogProxy(Object obj) { this.obj = obj; } /** * proxy 代理对象 * method 被调用的方法 * args 实参列表 * return 调用方法之后的返回值 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始日志"); //相当于之前的super.move() method.invoke(obj, args); System.out.println("结束日志"); return null; } }4、测试
package com.xjion.dynamicproxy; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { // Moveable car=(Moveable) Proxy.newProxyInstance(Car.class.getClassLoader(), // Car.class.getInterfaces(), new LogProxy(new Car())); // car.move(); Flyable aircraft=(Flyable) Proxy.newProxyInstance(Aircraft.class.getClassLoader(), Aircraft.class.getInterfaces(), new LogProxy(new Aircraft())); aircraft.fly(); } }Proxy.newProxyInstance()方法接受三个参数:
ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法1、汽车移动
package com.xjion.cglibproxy; import java.util.Random; public class Car{ public void move() { try { System.out.println("汽车移动中..."); Thread.sleep(new Random().nextInt(2000)); } catch (Exception e) { e.printStackTrace(); } } }2、飞机飞行
package com.xjion.cglibproxy; import java.util.Random; public class Aircraft{ public void fly() { try { System.out.println("飞机在飞飞飞..."); Thread.sleep(new Random().nextInt(2000)); } catch (Exception e) { e.printStackTrace(); } } }3、代理
package com.xjion.cglibproxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class TimeProxy implements MethodInterceptor{ /** * 提供返回代理对象的方法 */ public Object getProxy(Class clazz){ //创建代理对象工具实例 Enhancer enhancer=new Enhancer(); //设置被代理对象的反射对象 enhancer.setSuperclass(clazz); //调用回调函数 enhancer.setCallback(this); //返回代理对象 return enhancer.create(); } /** * obj 被代理的对象 * method 被代理的方法 * args 调用方法的实参 * proxy 代理对象 * * 返回值是 调用方法后的返回值 */ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { long startTime=System.currentTimeMillis(); //调用被代理的方法 proxy.invokeSuper(obj, args); long endTime=System.currentTimeMillis(); System.out.println("汽车运行结束,使用时间为"+(endTime-startTime)+"毫秒!"); return null; } }4、测试
package com.xjion.cglibproxy; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { // Car car=(Car) new TimeProxy().getProxy(Car.class); // car.move(); Aircraft aircraft=(Aircraft) new TimeProxy().getProxy(Aircraft.class); aircraft.fly(); } }
两种静态代理:
1、可以在符合开闭原则的情况下对目标进行功能扩展
2、不易于管理,接口变实现类也会变
JDK动态代理:
1、减少开发任务
2、降低对接口的依赖,从而降低了耦合度
3、CHLIB创建动态代理对象性能低
4、创建对象花费时间少
CGLIB代理:
1、使用字节码技术
2、CHLIB创建动态代理对象性能高
3、创建对象花费时间多
4、适合创建单例对象
装饰器模式:
1、不改变接口动态扩展功能
2、将对象传递给Decorator的构造函数使用
3、增强自身的功能
代理模式:
1、提供代理对象,不改变接口控制对象的访问
2、创建真实对象的实例
3、让比尔去做一些和本身业务没有太多关系的职业
1、都是实现同一个接口,一个类包装另一个类
2、都是对类的方法进行扩展