目录
1 介绍
一个类代表另一个类的功能。
2 静态代理模式
2.1 例子
2.1.1 授课接口
//授课
interface Teach{
void teach();
}
2.1.2 老师类
//老师类
class Teacher implements Teach{
public void teach(){
System.out.println("老师正在上课");
}
}
2.1.3 代理老师(核心)
//代理上课
class TeacherProxy implements Teach{
private InterFaceTeach target;//目标对象
//构造方法
TeacherProxy(InterFaceTeach target){
this.target=target;
}
@Override
public void teach() {
System.out.println("代理开始");
target.teach();//代理,表面是代理在教书,实际上是老师在教书
System.out.println("代理结束");
}
}
对外感觉是代理老师在上课,实际上代理老师还是找目标老师来上课的。注意和适配器模式的区别,适配器模式目标类没有实现要使用的接口,仅仅是适配器类在实现,而代理模式目标和代理都实现了要使用的接口。适配器的目标对象是继承或组合来的,而代理的目标对象是聚合来的。
2.1.4 测试主类
public class Main{
public static void main(String[] args) {
//代理前
Teacher teacher=new Teacher();
teacher.teach();
//代理后
TeacherProxy teacherProxy=new TeacherProxy(teacher);
teacherProxy.teach();
}
}
运行结果:
老师正在上课
代理开始
老师正在上课
代理结束
2.2 总结
静态代理方式的核心在于目标类和代理类都实现了同一个接口方法,然后代理类聚合目标类,对外看似使用代理的方法,实则使用的还是目标对象的方法。
3 动态代理
3.1 java反射
- 使用动态代理需要有java反射的基础:java注解与反射
- 动态代理需要使用的工具包:
java.lang.reflect.Proxy
和java.lang.reflect.InvocationHandler
(基于接口)、cglib
(基于类)、javasist
(java字节码实现); - 动态代理的类是动态生成的,不是我们直接写好的;
3.2 基于接口的动态代理(JDK代理)
需要使用java.lang.reflect.Proxy
和java.lang.reflect.InvocationHandler
两个类;
3.2.1 InvocationHandler接口
- 是一个接口;
- 该仅仅只有一个方法:
Object invoke(Object proxy, Method method, Object[] args)
,参数含义:proxy具体的代理实例,method代理实例的方法,args代理方法的参数列表,Object执行之后的返回结果对象;
每个代理实例都有一个关联的调用处理程序,当代理实例调用方法时,方法调用将被编码分配并分派到调用处理程序的invoke
方法。
3.2.2 Proxy类
全是静态方法。
static InvocationHandler getInvocationHandler(Object proxy)
:返回代理的对象的InvocationHandler
,用于执行代理方法。static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
:返回代理类,传入类加载器和代理接口。static boolean isProxyClass(Class<?> cl)
:判断一个类是不是代理类。static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
:传入类加载器,类代理的接口,执行代理方法的接口。输出一个代理对象。
3.2.3 实现代理管理者类
// 代理管理者机构
class ProxyManager implements InvocationHandler{
// 被代理的接口
private Object target;
//真实对象传进来
public void setTarget(Object target) {
this.target = target;
}
// 获得代理实例
public Object getProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
}
// 代理执行方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理开始");
//利用反射机制调用目标对象的方法
Object out=method.invoke(target,args);
System.out.println("JDK代理提交");
return out;
}
}
注意点:当获取代理实例的时候,必须要有一个InvocationHandler
的实现,当代理执行所有接口方法的时候,都会执行invoke
实现的方法
3.2.4 测试主类
public class Main {
public static void main(String[] args) {
// 被代理对象
Teacher teacher = new Teacher();
// 创建代理
ProxyManager proxyTeacher = new ProxyManager();
// 把真正的老师设置进去
proxyTeacher.setTarget(teacher);
// 获得代理老师
Teach instance = (Teach) proxyTeacher.getProxyInstance();
// 执行方法
instance.teach();
}
}
注意点:动态代理精髓在于被代理对象可以是多变的,可就是动态的灵魂,而静态代理每代理一种类就要去实现一个代理类,也就是说ProxyManager
这个模板是可以不动的,只需要setTarget()
不同的被代理对象即可。
3.3 总结
静态代理的弊端是每新增一种代理,就需要编写实现一个代理类,比如学生代理,老师代理等等。而动态代理利用java的反射机制,只需要实现一个代理管理者,当需要代理不同的对象的时候,只需要把这个对象set进去即可,不需要再编写代理类,唯一要注意的就是jdk代理是基于接口实现的,所以这些被代理的对象都需要以实现接口的方式。
4 Cglib代理
待更新。。。