代理模式(Proxy Pattern)是 java 常用 设计模式 之一。其定义:为其他对象提供一种代理以控制对这个对象的访问,即是:使用代理模式创建代理对象,让代理对象控制目标对象的访问(目标对象可以是远程的对象、创建开销大的对象或需要安全控制的对象),并且可以在不改
变目标对象的情况下添加一些额外的功能。
UML类图:
模式中包含的角色及其职责说明:
Subject:抽象主题角色,抽象主题类可以是抽象类,也可以是接口,是一个最普通的业务类型定义,无特殊要求。
RealSubject:具体主题角色,也叫被委托角色、被代理角色。是业务逻辑的具体执行者。
Proxy:代理主题角色,也叫委托类、代理类。它把所有抽象主题类定义的方法给具体主题角色实现,并且在具体主题角色处理完毕前后做预处理和善后工作。(最简单的比如打印日志)
代码实现一:
1、Subject
/** * 抽象主题,定义主要功能 */public interface Subject { public void operate();}
2、RealSubject
/** * * 具体主题 */public class RealSubject implements Subject{ @Override public void operate() { System.out.println("realsubject operatestarted......"); } }
3、Proxy
/** * 代理类 */public class Proxy implements Subject{ private Subject subject; public Proxy(Subject subject){ this.subject = subject; } @Override public void operate() { System.out.println("before operate......"); subject.operate(); System.out.println("after operate......"); }}
4、ProxyClient
** * 代理模式-测试客户端 */public class ProxyClient { public static void main(String[] args) { Subject subject = new RealSubject(); Proxy proxy = new Proxy(subject); proxy.operate(); } }
运行结果:
Java 动态代理(转自:)
在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的我们的功能,我们更需要学习的是其底层是怎么样的一个原理,而AOP的原理就是java的动态代理机制。
在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。首先我们先来看看java的API帮助文档是怎么样对这两个类进行描述的:
InvocationHandler:
InvocationHandler is the interface implemented by the invocation handler of a proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
解释:每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法;
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
Object invoke(Object proxy, Method method, Object[] args) throws Throwableproxy: 指代我们所代理的那个真实对象method: 指代的是我们所要调用真实对象的某个方法的Method对象args: 指代的是调用真实对象某个方法时接受的参数
Proxy:
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.
Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法;
public static Object newProxyInstance(ClassLoader loader, Class [] interfaces, InvocationHandler h) throws IllegalArgumentException
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
public static Object newProxyInstance(ClassLoader loader, Class [] interfaces, InvocationHandler h) throws IllegalArgumentExceptionloader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
代码实例:
/** * 代理接口 */public interface Subject { public void rent(); public void hello(String str); }
/** * 真实对象 */public class RealSubject implements Subject{ @Override public void rent() { System.out.println("I want to rent my house"); } @Override public void hello(String str) { System.out.println("hello: " + str); }}
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;/** * 动态代理对象 */public class DynamicProxy implements InvocationHandler{ //这是我们要代理的真实对象 private Object subject; public DynamicProxy(Object subject){ this.subject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在代理真实对象前我们可以添加一些自己的操作 System.out.println("before rent house"); System.out.println("Method:" + method); //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 method.invoke(subject, args); //在代理真实对象后我们也可以添加一些自己的操作 System.out.println("after rent house"); return null; }}
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;/** * 动态代理-测试 */public class DynamicProxyClient { public static void main(String[] args) throws InstantiationException, IllegalAccessException { // 我们要代理的真实对象 Subject realSubject = new RealSubject(); // 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的 InvocationHandler handler = new DynamicProxy(realSubject); /* * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数 * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象 * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 * 第三个参数handler, 是将这个代理对象关联到了上方的 InvocationHandler 这个对象上 */ Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler); System.out.println(subject.getClass().getName()); subject.rent(); subject.hello("world"); } }
打印结果:
说明: 1、$Proxy0 这东西,我们看到,这个东西是由 System.out.println(subject.getClass().getName()); 这条语句打印出来的,
Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject .getClass().getInterfaces(), handler);可能我以为返回的这个代理对象会是Subject类型的对象,或者是InvocationHandler的对象,结果却不是,首先我们解释一下为什么我们这里可以将其转化为Subject类型的对象?原因就是在newProxyInstance这个方法的第二个参数上,我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现了这组接口,这个时候我们当然可以将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是Subject类型,所以就可以将其转化为Subject类型了。
同时我们一定要记住,通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。
2、subject.rent();
subject.hello("world");这里是通过代理对象来调用实现的那种接口中的方法,这个时候程序就会跳转到由这个代理对象关联到的 handler 中的invoke方法去执行,而我们的这个 handler 对象又接受了一个 RealSubject类型的参数,表示我要代理的就是这个真实对象,所以此时就会调用 handler 中的invoke方法去执行:
3、我们看到,在真正通过代理对象来调用真实对象的方法的时候,我们可以在该方法前后添加自己的一些操作,同时我们看到我们的这个 method 对象是这样的:
public abstract void com.xiaoluo.dynamicproxy.Subject.rent()public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)
小结:
正好就是我们的Subject接口中的两个方法,这也就证明了当我通过代理对象来调用方法的时候,起实际就是委托由其关联到的 handler 对象的invoke方法中来调用,并不是自己来真实调用,而是通过代理的方式来调用的,这就是我们的java动态代理机制。