代理
- 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象,在代理对象中调用目标对象,从而实现对目标对象的增强.
- 代理模式:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式的应为叫做Proxy或Surrogate,它是一种对象结构型模式。–《Java设计模式深入研究》
一 静态代理
- JAVA静态代理的代理类在编译期就已经存在。
- 静态代理:
- 抽象主体角色:它的作用是定义一组行为规范。抽象角色一般呈现为接口(或抽象类),这些接口(或抽象类)中定义的方法就是待实现的。
- 真实主体角色:实现接口所定义的方法。
- 代理角色:实现目标类实现的相同接口中的方法,在代理类中调用目标类中的方法,实现对目标类的增强
- 示例代码
定义接口(抽象主体角色)
public interface Subject {
void helloWorld(String str);
}
接口实现类(真实主体角色)
public class SubjectImpl implements Subject {
@Override
public void helloWorld(String str) {
System.out.println("hello World: "+str);
}
}
代理类(代理角色)---需要和真实主体角色实现相同接口
public class SubjectImplProxy implements Subject {
private SubjectImpl subject;
public SubjectImplProxy(SubjectImpl object) {
this.subject = object;
}
@Override
public void helloWorld(String str) {
System.out.println("----before----");
subject.helloWorld(str);
System.out.println("----after-----");
}
}
调用
public static void main(String[] args) {
Subject subject = new SubjectImplProxy(new SubjectImpl());
subject.helloWorld("static");
}
调用结果
----before----
hello World: static
----after-----
- 优缺点
- 优点:调用方只需要知道代理类怎么实现(具体怎么调用委托类由代理类决定),不需要了解委托类怎么实现
- 缺点:
- 代理类和委托类实现了相同的接口,如果接口添加或者删除方法,委托类和代理类都要做出更改,后期维护会很复杂。
- 代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。
二 动态代理
- 动态代理是在运行期利用JVM的反射机制生成代理类
- JDK的动态代理只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。(如果需要代理没有实现接口的对象需要使用Cglib代理)
- 实现动态代理需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类
java.lang.reflect.InvocationHandler
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
- Object proxy:方法在其上调用的代理实例
- Method method:实例对应于在代理实例上调用的接口方法
- Object[] args:在代理实例上的方法调用中传递的参数
java.lang.reflect.Proxy
public static Object newProxyInstance(ClassLoader loader,Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException
- ClassLoader loader:产生代理对象的类加载器
- Class<?>[]interfaces:代理类实现的接口列表
- InvocationHandler h:这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
- 示例代码
public class MyInvocationHandler implements InvocationHandler {
private Object targetObject;
public Object newProxyInstance(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
}
public MyInvocationHandler() {
}
public MyInvocationHandler(Object targetObject) {
this.targetObject = targetObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("----before----");
method.invoke(targetObject, args);
System.out.println("----after----");
return null;
}
}
调用
public static void main(String[] args) {
Subject subject = new SubjectImplProxy(new SubjectImpl());
subject.helloWorld("static");
System.out.println("-----------------------------------------------------------");
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
Subject dynamicSubject = (Subject) myInvocationHandler.newProxyInstance(new SubjectImpl());
System.out.println(dynamicSubject.getClass().getName());
dynamicSubject.helloWorld("dynamic");
}
调用结果
----before----
hello World: static
----after-----
-----------------------------------------------------------
com.sun.proxy.$Proxy0
----before----
hello World: dynamic
----after----
- 优点:和静态代理相比,动态代理可以代理多个类型的接口,复用性强,并且当目标对现象需要实现的方法比较多的时候,动态代理不需要像静态代理一样对每一个方法进行中转。
总结
- jdk动态代理完全的实现了代理模式的设计理念,静态代理和动态代理用不同的方式生成了相同功能的代理类,只不过静态代理需要针对每一个目标对象创建不同的代理类,动态代理可以根据不同的目标对象动态的生成代理类更加的灵活。spring的aop就是基于代理实现的。