类的代理常见模式
1.继承代理
2.聚合代理(实现接口的方式)
3.动态代理(反射,实现接口)
4.cglib代理(针对类实现的代理)
具体实现代码如下
继承的方式代理
(1)被代理的对象Car
class Car {
//move方法
public void move(){
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("car is sleeping");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(2)代理类继承被代理对象
class StartCar extends Car {
//重写move方法,在方法体重又调用父类的move方法,在父类的move方法调用前后输出字符串
@Override
public void move(){
System.out.println("---开始前-----");
super.move();
System.out.println("----结束后----");
}
}
(3)测试继承代理
class Client {
public static void main(String[] args) {
StartCar startCar = new StartCar();
startCar .move();
}
}
总结:继承的方式代理类,我的理解就是子类继承父类同事也继承了父类所有的方法和成员变量,只是 在重写父类的方法时可以稍作修改。 这种方式实现代理缺点就是一个子类只能继承一个父类,并且如果需要实现多功能的代理或者实现的功能的顺序有变化时,就要不停的创建类,这样会导致类爆炸。
例如:第一次我要在实现父类的move方法前提醒开始和结束。
第二次我要在提示开始和结束前打印日志。
第三次我要实现先打印日志在提示开始结束在执行move方法。
聚合的方式代理类
(1)一个接口Moveable,让被代理的对象实现
interface Moveable {
void move();//定义了一个没有实现的方法
}
(2)Car类被代理的对象,它实现了接口Moveable,实现了其中的方法
class Car implements Moveable{
@Override
public void move(){
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("car is sleeping");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(3)代理类
class ProxyCar extends Car {
private Moveable m;//私有属性
ProxyCar(Moveable m){
this.m = m;
}
@Override
public void move(){
System.out.println("---开始前-----");
m.move();
System.out.println("----结束后----");
}
}
(4)测试实现接口代理
class Client {
public static void main(String[] args) {
Car car = new Car();
ProxyCar proxyCar = new ProxyCar(car);
proxyCar.move();
}
}
总结:实现接口的方式实现代理,大致思路与继承的方式实现代理类似,只是由继承类变为实现接口实现代理。 两者的区别 我自己认为就是类继承的单一性与接口继承的多样性,一个类只能继承一个父类,而一个类可以实现很多接口,重复步骤(3),调用时改变调用的顺序即可
JDK动态代理的实现
(1).被代理对象将要实现的接口Moveable;
interface Moveable {
void move(); //没有方法体的move方法
}
(2)被代理的对象Car,实现接口Moveable;
class Car implements Moveable{
@Override
public void move(){ //实现接口中的move方法
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("----car is go for a rest at now-----");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(3)连接被代理对象Car与代理类的桥梁 CarHandler类 实现 InvocationHandler接口
class CarHandler implements InvocationHandler {
private Object target; //
public CarHandler(Object target){
this.target =target;
}
/**
* invoke 方法实现自InvocationHandler接口,该方法的三个参数的含义
* 1.proxy被代理的对象
* 2.method 被代理对象的特定方法,改方法将通过代理的方式执行
* 3.args 一个数组,是被代理的方法的参数列表,当只有一个参数时可以直接传递,
* 也可以创建一个数组并在该数组中添加一个唯一的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
System.out.println("-----------");
method.invoke(this.target);
//该步骤旨在执行被代理对象的指定方法,若改方法有返回值,就将返回值返回,若没有就返回null
return null;
}
}
(4)主方法调用同过代理类Proxy.newProxyInstance方法创建被代理类Car的实例,实现Car类的动态理
class Client {
public static void main(String[] args) {
Car car = new Car();//创建被代理对象的实例
InvocationHandler handler = new CarHandler(car);//通过桥梁连接被代理对象与代理类
/**
* Proxy代理类
* Proxy.newProxyInstance()创建被代理对象的实例,该方法有三个参数
* 1.ClassLoader被代理类的类加载器
* 2.Class<?>[] interface 被代理的对象实现的接口,是一个Class的数组
* 3.InvocationHandler 连接被代理对象与代理之间的桥梁
*
*/
Moveable m= (Moveable)Proxy.newProxyInstance(car.getClass().getClassLoader(), new Class[]{Moveable.class}, handler);
m.move();
}
}
总结:JDK的动态代理只能代理实现接口的类,没有实现接口的类就不能代理,即使这样比起继承和聚合的方式代理对象,方便了许多,动态代理其实也就是将一类具有类似的特性的类代理实现其功能。例如:交通工具,特征是可以移动但是不同的交通工具有不同的实体,像火车,高铁,自行车,小汽车,自行车等。交通工具就像是一个接口,这个实体相当于实现了这个接口,代理类Proxy呢并不知道确切的是哪个具体的类要调用方法但是根据反射就会得到该实体的实例,并调用相应的方法
cglib代理(针对类实现的代理)
(1)被代理的对象Car
class Car{
//Car类的move方法
public void move(){
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("car is on sleep ");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(2)CglibProxy 实现MethodInterceptor 接口并实现了intercept方法这个步骤比较繁琐,当然每一个步骤都有注释
public class CglibProxy implements MethodInterceptor {
Enhancer enhancer = new Enhancer();
/**
* @param superclass 被代理的对象
* @return 代理类,也就是被代理对象的子类
*/
public Object getProxy(Class superclass){
//设置创建子类的类,确定创建的代理类,代理的是哪个被代理的对象
enhancer.setSuperclass(superclass);
//设置回调
enhancer.setCallback(this);
//创建子类,将子类返回
return enhancer.create();
}
/**
* 拦截所有目标类方法的调用,四个参数的含义
* obj 被代理的类的对象
* method 被代理类指定的方法
* args 方法的参数
*proxy 代理的类的实例
*/
@Override
public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {
/**
* 代理类调用父类的方法,cglib使用继承的方式实现代理,所以产生类是被代理对像的子类
* obj与proxy之间的关系是 obj是proxy的父类,proxy继承了obj
*/
System.out.println("---开始调用---");
proxy.invokeSuper(obj, args);
System.out.println("---结束调用----");
return null;
}
}
(3)测试代理
public class Client {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();//实现拦截接口的类
//得到CglibProxy的getProxy方法创建Car类的子类的实例,具体的实现看步骤2,;
Car car =(Car) cglibProxy.getProxy(Car.class);
//子类的实例调用父类的move()实现代理
car.move();
}
}