JDK的代理模式

jdk的代理模式
1.代理模式的定义:
为其他对象提供一种代理一控制对这个对象的访问,代理对对象起到中介作用,用于去掉部分功能服务或者是增加一些额外的服务
2.静态代理:
代理和被代理之间的关系是确定的,他们都是实现相同的接口或者是继承相同的抽象类;
JDK的代理模式
JDK的代理模式

创建接口

public interface Moveable {
void move();
}
创建车实现Moveable方法

public class Car implements Moveable {
@Override
public void move() {
//实现开车
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
① 继承的方式:
创建Car2_以继承的方式实现静态代理:

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("汽车结束行驶.... 汽车行驶时间:"
+ (endtime - starttime) + "毫秒!");
}
}
② 聚合的方式:
创建Car3__以聚合的方式实现静态代理:

public class Car3 implements Moveable {
public Car3(Car car) {
super();
this.car = car;
}
private Car car;
@Override
public void move() {
long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶....");
car.move();
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶.... 汽车行驶时间:"
+ (endtime - starttime) + "毫秒!");
}
}
两者之间都可以实现静态代理,但是相比之下,使用聚合的方式更好:
比如: 上面的例子只是增加了时间记录那么需要创建一个Car2,那么如果在增加一个记录行驶日志呢?那么就要再创建一个Car4,再增加一个权限呢?那么就需要再创建一个Car5来继承Car4,.........这样的话没增加一个功能就需要创建一个实例.但是使用聚合的方式就不会这样了
同样创建一个move接口:

public interface Moveable {
void move();
}
再创建一个实例Car实现Moveable接口

public class Car implements Moveable {
@Override
public void move() {
//实现开车
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
创建时间代理_用于记录时间

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) + "毫秒!");
}
}
创建日志代理_用于记录日志

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("日志结束....");
}
}
JDK的代理模式
创建测试类

public static void main(String[] args) {
Car car = new Car();
CarLogProxy clp = new CarLogProxy(car);
CarTimeProxy ctp = new CarTimeProxy(clp);
clp.move();//此时是先执行日志,再执行记录行驶时间
ctp.move();//此时是先执行记录行驶时间,再执行记录日志
}
这样可以看出聚合相比于继承要灵活了很多
但是,像权限,日志,时间这种公共的代理,后面如果再创建了一个其他对象,如飞机,火车,自行车呢?那是不是就要创建不同的实例呢?然后这种情况下就需要用到动态代理了
3.动态代理
动态代理的原理图如下所示:
JDK的代理模式
Java动态代理类位于java.lang.reflect包下,一般主要涉及到一下两个类:
(1) Interface InvocationHandler :
该接口中仅定义了一个方法:public object invoke (Object obj,Method method, Object[] args)在实际使用的时候,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组,这个抽象方法在代理类中被动态实现;
(2)Proxy :
该类即为动态代理类
static Object newProxyInstance(ClassLoader loader,Class[] interf aces,
InvocationHandler h): 返回代理类的一个实例,返回后的代理类可以当作被
代理类使用(可使用被代理类的在接口中声明过的方法)
示例:
创建时间处理的handler

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimeHandler implements InvocationHandler {
public TimeHandler(Object target) {
super();
this.target = target;
}
private Object 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;
}
}
JDK动态代理测试:

/**
* JDK动态代理测试类
*/
public static void main(String[] args) {
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Clas s<?> cls = car.getClass();
/**
* loader 类加载器
* interfaces 实现接口
* h InvocationHandler
*/
Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),
cls.getInterfaces(), h);
m.move();
}
总结:
动态代理实现步骤
1.创建一个实现接口InvocationHandler的类,它
必须实现i nvoke方法
2.创建被代理的类以及接口
3.调用Proxy的静态方法,创建一个代理类
newProxyInstance(ClassLoader loader,Class[]
interfaces,InvocationHandler h)
4.通过代理调用方法
动态代理实现思路
实现功能: 通过Proxy的newProxyInstance返回代理对象
1、声明一段源码(动态产生代理)
2、编译源码(JDK Compiler API),产生新的类(代理类)
3、将这个类load到内存当中,产生一个新的对象(代理对象)
4、return 代理对象