Posted on 2009-11-07 21:27
codingliyi 阅读(253)
评论(0) 编辑 收藏 所属分类:
Design Patterns
在了解动态代理之前,有必要先知道什么是静态代理。
1. 静态代理
在静态代理的实现中,代理对象与被代理对象都必须实现同一个借口,在代理对象中可以实现日志记录等相关服务,并在需要的时候在呼叫被代理对象。如此代理对象中就可以仅保留业务相关职责。
示例代码:
首先定义一个IHello接口:
1public interface IHello {
2 public void sayHello(String name);
3}
然后让实现业务逻辑的HelloSpeaker类实现IHello接口:
1public class HelloSpeaker implements IHello {
2 public void sayHello(String name) {
3 System.out.println("Hello, " + name);
4 }
5}
将日志记录功能放入代理对象中,代理对象同样也要实现IHello接口:
1import java.util.logging.*;
2
3public class HelloSpeakerProxy implements IHello {
4
5 private Logger logger = Logger.getLogger(this.getClass().getName());
6 private IHello helloObject;
7
8 public HelloSpeakerProxy(IHello hello){;
9 this.helloObject = hello;
10 }
11 public void sayHello(String name) {
12 logger.log(Level.INFO, "before sayHello");
13 helloObject.sayHello(name);
14 logger.log(Level.INFO, "after sayHello");
15 }
16}
编写测试程序:
1public class StaticProxyDemo {
2 public static void main(String[] args) {
3 HelloSpeakerProxy proxy = new HelloSpeakerProxy(new HelloSpeaker());
4 proxy.sayHello("codingliyi");
5 }
6// 运行结果:
7// 2009-11-7 21:21:55 SpringAOP.HelloSpeakerProxy sayHello
8// 信息: before sayHello
9// Hello, codingliyi
10// 2009-11-7 21:21:55 SpringAOP.HelloSpeakerProxy sayHello
11// 信息: after sayHello
12}
静态代理缺陷:代理对象的一个接口只服务于一种类型的被代理对象。如果要代理的方法很多,静态代理就无法胜任。
2. 动态代理
在JDK1.3之后加入了可协助开发动态代理功能的API,不必为特定对象与方法编写特定的代理对象。使用动态代理,可以使得一个处理者(Handler)服务于各个对象。
相关的接口和类有如下两个:
1.java.lang.reflect.InvocationHandler接口
该接口仅定义了一个方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
其中,proxy指代理类,method是被代理的方法,args指方法的参数。
2.java.lang.reflect.Proxy类;
该类最主要的方法:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
其中,loader指被代理类的类加载器;interfaces指被代理类实现的接口,h指方法调用的处理程序。
动态代理的示例代码如下:
DynamicProxyHandler.java
1public class DynamicProxyHandler implements InvocationHandler {
2 private Object delegate;
3
4 public DynamicProxyHandler(Object delegate){
5 this.delegate = delegate;
6 }
7
8 public Object invoke(Object proxy, Method method, Object[] args)
9 throws Throwable {
10 System.out.println("调用方法前");
11 Object result = method.invoke(delegate,args);
12 System.out.println("调用方法后");
13 return result;
14 }
15}
DynamicProxyDemo.java
1public class DynamicProxyDemo {
2 public static void main(String[] args) {
3 HelloSpeaker speaker = new HelloSpeaker();
4 IHello hello = (IHello)Proxy.newProxyInstance(speaker.getClass().getClassLoader(), speaker.getClass().getInterfaces(), new DynamicProxyHandler(speaker));
5 hello.sayHello("codingliyi");
6 }
7// 运行结果:
8// 调用方法前
9// Hello, codingliyi
10// 调用方法后
11}
动态代理的实战步骤:
a. 业务接口,一个Interface;
b. 实现业务接口的类,即被代理类;
c. 一个继承了java.lang.reflect.InvocationHandler的Handler类,里面维持了一个被代理对象的引用(Object类型),实现invoke()方法;
d. 使用Proxy.newProxyInstance()将Handler与被代理类关联,得到代理类,并强制转化为接口类型;
e. 调用该接口的方法。