代理模式定义: 为其他对象提供一种代理以控制对这个对象的访问.
远程代理:为不同地理的对象提供局域网代表对象
虚拟代理: 根据需要将资源消耗很大的对象进行延迟加载 当我们正真需要这个对象的时候再进行创建.
保护代理:控制对一个对象的权限
智能引用代理: 对代理对象提供一些额外的服务.
下面我来使用 静态代理和动态代理 分别实现 智能引用代理功能
静态代理: 代理和被代理对象在代理之前是确定的他们都实现了相同的接口或者继承了相同的抽象类。
场景1: 我们有一辆汽车 汽车有行驶的功能 而我们现在需要给汽车增加一个记录行驶时间 下面是具体实现:
package com.zs.spring.demo1;
//汽车行驶接口
public interface Moveable {
public void move();
}
下面是我们传统的做法没有使用到代理类
package com.zs.spring.demo1;
import java.util.Random;
public class Car implements Moveable {
public Car() {
// TODO Auto-generated constructor stub
}
//行驶方法
@Override
public void move() {
long begen= System.currentTimeMillis();
// TODO Auto-generated method stub
System.out.println("汽车开始行驶");
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("汽车结束用时"+(end-begen)+"毫秒");
}
public static void main(String[] args) {
Car c =new Car();
c.move();
}
}
控制台:
汽车开始行驶
汽车行驶中
汽车结束用时701毫秒
下面是静态代理实现:
package com.zs.spring.demo1;
import java.util.Random;
public class Car2 extends Car{
@Override
public void move() {
long begen= System.currentTimeMillis();
// TODO Auto-generated method stub
System.out.println("汽车开始行驶");
super.move();
long end = System.currentTimeMillis();
System.out.println("汽车结束用时"+(end-begen)+"毫秒");
}
}
上面我们使用了继承来实现代理 新建Car2这个类 并且继承Car
重写move()方法 在子类中调用父类的行驶方法 而记录行驶时间就放到了Car2子类来做了。
下面我们来使用聚合方式做代理 所谓聚合方式就是一个类中调用了另外一个类就叫聚合.
package com.zs.spring.demo1;
public class Car3 implements Moveable{
private Car car;
public Car3(Car car){
this.car=car;
}
@Override
public void move() {
long begen= System.currentTimeMillis();
System.out.println("汽车开始行驶");
car.move();
long end = System.currentTimeMillis();
System.out.println("汽车结束用时"+(end-begen)+"毫秒");
}
public static void main(String[] args) {
Car c =new Car();
Car3 car3 =new Car3(c);
car3.move();
}
}
上面这种代理就是把Car类和代理类Car3同样的实现了Moveable 接口
在代理类中定义一个Car类对象 在使用的时候先将Car类交给Car3代理类
增加记录时间的特性.
诚然 继承的方式也有缺陷:比如 我们不光需要加时间代理 还要加日志代理和权限代理 那么是不是又要重新建立 日志代理类 和权限代理类呢 如果我们要 先记录 日志–时间–权限 那么就得 日志代理类继承Car 时间代理类继承日志类 权限代理类继承时间代理类 一层层的继承做代理,并且如果我们可能 先记录 时间-日志-权限 那么是不是我们又要重新写一套 扩展性太低.
下面我们使用 聚合代理方式模拟实现 日志 和时间代理
//日志代理类
package com.zs.spring.demo1;
public class CarLogProxy implements Moveable{
private Moveable car;
public CarLogProxy(Moveable car){
this.car=car;
}
@Override
public void move() {
System.out.println("日志开始......");
car.move();
System.out.println("日志结束......");
}
}
时间代理类
package com.zs.spring.demo1;
public class CarTimeProxy implements Moveable{
//因为日志类还是car类还是时间类都实现了Moveable接口所以定义接口
使用多态
private Moveable car;
public CarTimeProxy(Moveable car){
this.car=car;
}
@Override
public void move() {
long begen= System.currentTimeMillis();
System.out.println("汽车开始行驶");
car.move();
long end = System.currentTimeMillis();
System.out.println("汽车结束用时"+(end-begen)+"毫秒");
}
public static void main(String[] args) {
Car c =new Car();
CarTimeProxy car3 =new CarTimeProxy(c);
CarLogProxy clp = new CarLogProxy(car3);
clp.move();
}
}
控制台输出:
日志开始......
汽车开始行驶
汽车行驶中
汽车结束用时606毫秒
日志结束......
那么现在是先开始记录日志在记录时间 我现在想先记录时间再记录日志怎么做 不用像继承一样再写一套代理类继承
public static void main(String[] args) {
Car c =new Car();
CarLogProxy clp = new CarLogProxy(c);
CarTimeProxy car3 =new CarTimeProxy(clp);
car3.move();
}
控制台输出:
汽车开始行驶
日志开始......
汽车行驶中
日志结束......
汽车结束用时852毫秒
所以我们尽量使用聚合代理 扩展性高
动态代理:
所谓动态代理是在运行时生成class 该class需要实现一组接口(interface) 使用动态代理类时 必须实现
InvocationHandler接口
package com.zs.spring.demo1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class CarHandle implements InvocationHandler{
private Object target;
public CarHandle(Object target) {
this.target=target;
}
/**
* 参数:
* proxy:被代理的对象
* method:被代理对象的方法
* args[] 方法的参数
* 返回值:object
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
long begen= System.currentTimeMillis();
System.out.println("开始行驶");
method.invoke(target);
long end = System.currentTimeMillis();
System.out.println("结束行驶"+(end-begen)+"毫秒");
return null;
}
public static void main(String[] args) {
//创建被代理对象
Car c =new Car();
//要代理的对象给事件代理类CarHandle
InvocationHandler invo = new CarHandle(c);
//获取class对象
Class> invoCalss =c.getClass();
/**
* loader 被代理类
* interface 被代理类实现接口
* h 代理类 CarHandle
*/
Moveable m =(Moveable) Proxy.newProxyInstance(invoCalss.getClassLoader(),invoCalss.getInterfaces(),invo);
m.move();
}
}
控制台输出
汽车开始行驶
汽车行驶中
汽车结束用时133毫秒
以上为JDK使用 InvocationHandler实现的动态代理 这个样子不管是汽车类还是火车飞机 我们都能获取到他的行驶时间 也就是说能代理任何类