Posted on 2009-11-07 21:27
codingliyi 阅读(254)
评论(0) 编辑 收藏 所属分类:
Design Patterns
在了解动态代理之前,有必要先知道什么是静态代理。
1. 静态代理
在静态代理的实现中,代理对象与被代理对象都必须实现同一个借口,在代理对象中可以实现日志记录等相关服务,并在需要的时候在呼叫被代理对象。如此代理对象中就可以仅保留业务相关职责。
示例代码:
首先定义一个IHello接口:
1
public interface IHello
{
2
public void sayHello(String name);
3
}
然后让实现业务逻辑的HelloSpeaker类实现IHello接口:
1
public class HelloSpeaker implements IHello
{
2
public void sayHello(String name)
{
3
System.out.println("Hello, " + name);
4
}
5
}
将日志记录功能放入代理对象中,代理对象同样也要实现IHello接口:
1
import java.util.logging.*;
2
3
public 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
}
编写测试程序:
1
public 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
1
public 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
1
public 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. 调用该接口的方法。