代理模式

mac2025-06-12  29

概念

为其他类提供一种代理,以控制对这个类的访问

代理可以理解为助理,中介等,你想找直接领导只能找中间者,然后通过中间者去找领导

在面向对象系统中,有些对象由于(创建对象开销大、操作安全控制、需要进程外的访问)等一系列的问题,直接访问会带来很多麻烦,所以我们在访问此对象时加上一个此对象的访问层

角色

抽象角色:通过接口或抽象类声明真实角色实现的业务方法

代理角色:实现抽象角色,是真实角色的代理

真实角色:实现抽象角色,定义真是角色需要实现的业务逻辑,供代理角色调用

设计与实现

设计思想:汽车移动,计时,日志

一、没有代理

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(); } }

四、实现InvocationHandler接口实现动态代理

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:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法

五、CGLIB代理

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、都是对类的方法进行扩展

最新回复(0)