代理(Proxy)
如果要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如,异常处理、日志、计算方法的运行时间、事物管理、等等,该如何做?
代理正是用于处理这类问题。
编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。(参看代理架构图)
以后采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类,还是代理类,这样以后很容易切换。
譬如,想要日志功能时就配置代理类,否则配置目标类,这样增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易。
使用代理示例代码:
class SayHello {
public void sayHello(){
System.out.println("hello");
}
}
class SayHelloProxy{
public void sayHello (){
long start = System.currentTimeMillis();
System.out.println("hello");
long end = System.currentTimeMillis();
}
}
代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码。
1 在调用目标方法之前
1 在调用目标方法之后
1 在调用目标方法之前后
1 在处理目标方法异常的catch块中
示例代码:
Class proxy{
public void sayHello(){
//系统功能代码
try{
target.sayHello();
}
catch(Exception e){
//系统功能代码
}
//系统功能代码
}
}
代理架构图
AOP
动态代理
要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情!
JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理。
JVM生成的动态类必须实现一个或多个接口,所以JVM生成的动态类只能用作具有相同接口的目标类的代理。
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,可以使用CGLIB库。
动态代理的工作原理图