代理模式的定义
静态代理
实现方式
1.继承
子类通过继承父类,在子类重写父类方法时,手动调用父类的方法,并在子类中对其增强。
-- 例子
子类Car2对父类Car进行代理:
2.聚合
实现同一个接口,并持有被代理的对象。
-- 例子
Class CarProxy implements Moveable{
private Car car;
public CarProxy(Car car){
this.car = car
}
@Override
public void move(){
前增强;
car.move();
后增强;
}
}
比较
聚合代理优于继承代理。因为实现功能叠加的情况下,聚合代理通过相互代理可以实现功能重用,而继承代理必须写多个类来实现多功能叠加。
-- 例子
- 共同接口 Moveable
public interface Moveable {
void move();
}
- 被代理类 Car
public class Car implements Moveable {
@Override
public void move() {
//实现开车
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 代理类1 --日志代理类 CarLogProxy
public class CarLogProxy implements Moveable {
public CarLogProxy(Moveable m) { // 传入共同实现的接口对象
super();
this.m = m;
}
private Moveable m;
@Override
public void move() {
System.out.println("日志开始....");
m.move();
System.out.println("日志结束....");
}
}
- 代理类2 --时间代理类 CarTimeProxy
public class CarTimeProxy implements Moveable {
public CarTimeProxy(Moveable m) { // 传入共同实现的接口对象
super();
this.m = m;
}
private Moveable m;
@Override
public void move() {
long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶....");
m.move();
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶.... 汽车行驶时间:"
+ (endtime - starttime) + "毫秒!");
}
}
- 测试类 Client
public class Client {
public static void main(String[] args) {
Car car = new Car();
CarLogProxy clp = new CarLogProxy(car);
// 因为实现共同的接口,这里传入的是日志代理对象,实现代理叠加
CarTimeProxy ctp = new CarTimeProxy(clp);
ctp.move();
}
}
-- 运行结果
动态代理
动态产生代理,实现对不同类,不同方法的代理。
-- 例子
- 接口 Moveable
public interface Moveable {
void move();
}
- 被代理类 Car
public class Car implements Moveable {
@Override
public void move() {
//实现开车
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 动态代理类 TimeHandler
public class TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
/*
* 参数:
* proxy 被代理对象
* method 被代理对象的方法
* args 方法的参数
*
* 返回值:
* Object 方法的返回值
* */
@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("汽车结束行驶.... 汽车行驶时间:"
+ (endtime - starttime) + "毫秒!");
return null;
}
}
- 测试类
public class Test {
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(); // 由于传入的InvocationHandler,代理对象调用被代理对象方法时,会自动触发代理类的`invoke`方法
}
}
-- 运行结果
动态代理类总结
动态代理实现步骤
cglib vs jdk
- jdk动态代理机制:只能代理实现某些接口的类,如果没有实现接口的类则不能使用JDK动态代理。
- cglib动态代理机制:针对类产生代理,原理就是为指定的目标类产生一个子类,子类通过方法拦截技术(覆盖父类的方法来实现功能的增强)拦截所有父类方法的调用(因为该种方式是使用继承方式,所以不能对final修饰的类进行代理)。
动态代理实现思路
实现功能:通过Proxy的newProxyInstance
返回代理对象
- 声明一段源码(动态产生代理):利用InvocationHandler动态地实现指定的业务逻辑。
通过
interface.getName().getClass().getMethod()
获取Method,再传入Method对象至invoke(Object obj, Method method)
,可实现对不同方法的代理。 - 编译源码(JDK Compiler API),产生新的类(代理类)
- 将这个类load到内存当中,产生一个新的对象(代理对象)
- return 代理对象
具体流程见 大鹏111 的课程笔记
参考: