Java基础:代理
目录
- 一、什么是代理模式?
- 1、代理模式的分类
- 2、静态代理和动态代理的区别
- 二、代理实现全过程
- 1、静态代理
- 2、动态代理
一、什么是代理模式?
代理模式:给定目标对象一个代理对象,并且由代理对象控制目标对象的引用。
“千万不要动别人的屎山代码”,或者,功能实现后不要修改代码。那如何在不动代码的前提下增加新的功能模块,代理可以实现这部分功能。
代理模式的主要作用:
1、避免直接访问目标对象,通过访问代理对象执行目标对象的方法。
2、增强目标对象的方法的功能。
1、代理模式的分类
代理模式分为静态代理和动态代理。
静态代理如下图:
一个代理类对应一个代理对象,并且一个代理对象对应一个目标对象,一个代理对象不能对应多个目标对象,不符合代理的一对一关系。
动态代理如下图:
一个代理类可以对应多个代理对象,一个代理对象对应一个目标对象,代理对象和目标对象的关系一一对应。
2、静态代理和动态代理的区别
静态代理:
代理类和目标类关系在编译时就确定。
需要编辑大量的代理类。
目标对象必须实现接口。
动态代理:
代理类和目标类的关系在运行时确定。
不需要手动编写代理类。
常用的是动态代理,因为不需要根据目标类自己重新的编辑大量的代理类,更加方便。
二、代理实现全过程
下面的过程将从一步一步从静态代理转变为动态代理的全过程,以方便更好的理解动态代理部分
1、静态代理
(1)构建目标类以及目标类当中的核心方法。
public class L1 {public void m1(){System.out.println("---L1");}
}
public class L2 {public void m2(){System.out.println("---L2");}
}
public class L3 {public void m3(){System.out.println("---L3");}
}
(2)构建代理类
首先以目标类1和代理类1入门,进行分析:
public class L {private L1 l1 = new L1();public void runL1(){l1.m1();}
}
(3)Test测试类定义如下:
public class Test {public static void main(String[] args) {L l = new L();l.runL1();}
}
上面的情况为静态代理的过程。一个代理类对应一个目标类。实现不访问目标类,也可以执行目标类中的核心方法。
经过上面的情况,可能会有人疑惑,我如果把所有的目标类对应到一个代理类当中,不就可以一个代理类控制所有的目标类了吗?这不就是动态代理了吗?
即下面的情况:
也就是下面如图:
可以明显的看出来,每一个代理对象都可以对应所有的目标对象,不符合一对一的对应关系,因此上面的情况不属于代理。
静态代理的内存图如下:
2、动态代理
因为一个代理类对应多个目标类,但是一个代理对象对应一个目标对象。所以代理类中的目标对象需要根据对应的情况进行改变。
(1)因此代理类中的代码需要修改如下:
利用多态的方式进行接收传输进来的目标对象,可以实现根据对应的目标对象,创建出来对应的代理类。
(2)获得目标类当中的核心方法
需要用到 java.lang.relfect.Proxy,获得对应的目标类的接口。
将上面的运行目标类的方法修改为下面的情况(需要配合InvocationHandler使用):
下面代码的三个参数分别为:
1、利用反射获得的类加载器。
2、被代理对象实现的接口,这个也可以通过被代理对象获取。
3、 当我们在执行被代理对象的方法的时候,这个处理器就会被执行,当这个方法被执行的时候,会将被代理对象,方法,参数都传入进去
public Object m1(){return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(),this);}
(3)重写接口InvocationHandler的方法
其中的三个参数都不需要自己填写,method为反射得到的,args是填写的参数,o是目标对象。
@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {method.invoke(o,args);return null;}
(4)运行结果
目标类对应的接口如下:
public interface L1Inter {public void m1();
}
public static void main(String[] args) {L1Inter l1 = (L1Inter) (new L(new L1())).LgetInter();l1.m1();}
利用L1对应的接口多态执行目标类的核心方法。