java设计模式之代理模式
java代理模式是一种常见的设计模式。
一、概念:为其他对象提供一种代理以控制对这个对象的访问。代理对象起到中介作用,可去掉功能服务或增加额外的服务。
二、常见的代理模式有哪些?
- 远程代理:为不同地理的对象,提供局域网代表对象。
- 虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建。
- 保护代理:控制对一个对象访问的权限。
- 智能引用代理:提供对目标对象额外的服务。
三、代理模式的两种实现方式
- 静态代理:代理和被代理对象在代理之前是确定的,他们都实现相同的接口或者继承相同的抽象类。
- 动态代理
四、示例
1.通过继承实现静态代理
首先,先写一个接口
public interface Moveable { void move(); }
然后写接口的实现类
public class Car implements Moveable { @Override public void move() { //实现开车 try { Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } }
接着是继承类,在继承类中,我们实现了父类中的方法,并增加了一些额外的功能,从而实现静态代理
public class Car2 extends Car{ @Override public void move(){ long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶.......");
//调用父类中的方法,实现该方法 super.move(); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶......"); System.out.println("汽车行驶时间:"+(endtime - starttime)+"毫秒!"); } }
测试方法
public class Test{ public static void main(String[] args) { //使用继承方式实现 Moveable m = new Car2(); m.move(); } }
2.通过聚合实现静态代理
编写聚合类(通过将参数传递进来,然后我们使用传递进来的参数,调用其方法,实现静态代理)
public class Car3 implements Moveable{ private Car car; public Car3(Car car) { super(); this.car = car; } @Override public void move() { long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶.......");
//通过构造方法将car传进来,然后通过car调用方法 car.move(); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶......"); System.out.println("汽车行驶时间:"+(endtime - starttime)+"毫秒!"); } }
测试方法
public class Test { public static void main(String[] args) { //使用聚合方式实现 Car car = new Car(); Moveable m = new Car3(car); m.move(); } }
使用继承实现静态代理,会让我们的代理类无限制的膨胀下去,所以推荐使用聚合实现静态代理。
五、JDK动态代理
1.定义
在代理类和被代理类之间加上一个事务处理器,将我们需要处理的具体功能放在其中进行处理。
InvocationHandler接口(事务处理器)中仅定义了一个方法public object invoke(Object obj,Method method,Object[] args),在实际使用中,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组,这个抽象方法在代理类中动态实现。
Proxy:该类即为动态代理类,通过newProxyInstance方法可以返回代理类的一个实例,返回后的代理类可以当做被代理类使用(可使用被代理类的在接口中声明过的方法)。
2.实现步骤
- 创建一个实现接口InvocationHandler的类,它必须实现invoke方法,在invoke方法中添加具体的业务逻辑。
- 创建被代理的类和接口。
- 调用Proxy的静态方法newProxyInstance,动态创建一个代理类。
- 通过代理调用方法。
3.示例
public class TimeHandler implements InvocationHandler{ private Object target; public TimeHandler(Object target) { super(); this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶......."); method.invoke(target); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶......"); System.out.println("汽车行驶时间:"+(endtime - starttime)+"毫秒!"); return null; } }
public class TestProxy { public static void main(String[] args) { Car car = new Car(); InvocationHandler h = new TimeHandler(car); Class<?> cls = car.getClass(); /** * loader 类加载器 * interfaces 实现接口 * h InvocationHandler * */ Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h); m.move(); } }
六、CGLIB动态代理
示例:
首先需引入cglib的jar包
对应的实体类
public class Train { public void move(){ System.out.println("火车行驶中........."); } }
public class CglibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); //创建代理类 public Object getProxy(Class clazz){ //设置创建子类的类,为每个类产生代理类 enhancer.setSuperclass(clazz); //设置回调 enhancer.setCallback(this); //创建子类的实例并返回 return enhancer.create(); } /** * 拦截所有目标类方法的调用 * obj 目标类的实例 * m 目标方法的反射对象 * args 方法的参数 * proxy 代理类的实例 * */ @Override public Object intercept(Object obj, Method m, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("日志开始......"); //代理类调用父类的方法 proxy.invokeSuper(obj, args); System.out.println("日志结束......"); return null; } }
public class Test { public static void main(String[] args) { //创建返回代理类对象 CglibProxy proxy = new CglibProxy(); //为trian返回代理类对象 Train t = (Train) proxy.getProxy(Train.class); //调用方法 t.move(); } }
JDK动态代理和CGLIB动态代理的区别
JDK动态代理:
- 只能代理实现了接口的类。
- 没有实现接口的类不能实现JDK的动态代理。
CGLIB动态代理:
- 针对类来实现代理。
- 对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用。
动态代理的典型应用:spring AOP:同时用到了JDK动态代理和CGLIB动态代理。