介绍
代理模式是Java常见的设计模式之一,代理模式是指客户端不直接调用实际的对象,而是通过调用代理对象,间接调用实际对象,简单来说就是不改变源码的情况下,实现对实际对象的功能扩展。
一般客户端不想直接访问实际对象或访问实际对象存在困难,通过一个代理对象来完成间接访问。
代理模式的实现
代理模式可以有两种实现方式,我们根据加载被代理类的时机不同,将代理分为静态代理和动态代理。如果我们在代码编译时就确定了被代理的类是哪一个,那么就可以直接使用静态代理;如果不能确定,那么可以使用类的动态加载机制,在代码运行期间加载被代理的类这就是动态代理,比如RPC框架和Spring AOP机制。
静态代理
代理类接受一个接口的对象,任何实现该接口的对象都可以通过代理类进行代理,增加了通用性,如:
Subject 接口
public interface Subject {
void visit();
}
实现了Subject接口的两个类
目标对象
public class RealSubject implements Subject {
private String name = "yk";
@Override
public void visit() {
System.out.println(name);
}
}
代理对象
public class ProxySubject implements Subject{
private Subject subject;
public ProxySubject(Subject subject) {
this.subject = subject;
}
@Override
public void visit() {
subject.visit();
}
}
具体调用如下
public class Client {
public static void main(String[] args) {
ProxySubject subject = new ProxySubject(new RealSubject());
subject.visit();
}
}
静态代理也有缺点,每一个代理对象都必须实现一遍目标对象的接口,如果接口增加方法,则代理类必须跟着修改,其次代理类每一个接口对应一个目标对象,如果目标对象很多,则静态代理类就非常臃肿。
动态代理
动态代理区别于静态代理是根据代理的对象,动态创建代理类,这样避免静态代理中代理类接口过多的问题,动态代理实现的方式是通过反射来实现的,有两种=方式来时先动态代理:
JDK代理
JDK代理要实现java反射包下的一个接口InvocationHandler
package java.lang.reflect;
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
InvocationHandler接口中只有一个invoke方法我们通过代理类调用目标对象方法时,最终都会委托给这个invoke方法执行,所以我们就可以在这个invoke方法中对被代理类进行增强或做一些其他操作。
public class MyInvocationHandler implements InvocationHandler{
private Object object;
public MyInvocationHandler(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("MyInvocationHandler invoke begin");
System.out.println("proxy: "+ proxy.getClass().getName());
System.out.println("method: "+ method.getName());
for(Object o : args){
System.out.println("arg: "+ o);
}
//通过反射调用 被代理类的方法
method.invoke(object, args);
System.out.println("MyInvocationHandler invoke end");
return null;
}
在使用时创建目标对象和代理类对象,然后定义接口应用
jdk的代理让我们在不直接访问某些对象的情况下,通过代理机制也可以访问被代理对象的方法,这种技术可以应用在很多地方比如RPC框架,Spring AOP机制,但是我们看到jdk的代理机制必须要求被代理类实现某个方法,这样在生成代理类的时候才能知道重新那些方法。这样一个没有实现任何接口的类就无法通过jdk的代理机制进行代理,当然解决方法是使用cglib的代理机制进行代理