一、代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。
更通俗的说,代理解决的问题当两个类需要通信时,引入第三方代理类,将两个类的关系解耦,让我们只了解代理类即可,而且代理的出现还可以让我们完成与另一个类之间的关系的统一管理,但是切记,代理类和委托类要实现相同的接口,因为代理真正调用的还是委托类的方法。
二、静态代理
具体用户管理实现类
class UserServiceImpl implements IUserService{
@Override
public void doService() {
// TODO Auto-generated method stub
System.out.println("doing UserServiceImpl.doService");
}
}
代理类–代理用户管理实现类
//代理类 静态代理 功能的增强在代理中添加;
class UserServiceProxy implements IUserService{
//需要一个委托类的对象的引用;
private IUserService service;
//通过构造,传入目标对象
public UserServiceProxy(String name, IUserService service) {
super();
this.service = service;
}
@Override
public void doService() {
// TODO Auto-generated method stub
long begin = System.currentTimeMillis();
service.doService();
long end = System.currentTimeMillis();
System.out.println("spend time:" + (end-begin) + "ms");
}
}
客户端调用
public class StaticProxyTest {
public static void main(String[] args) {
IUserService service = new UserServiceProxy("zhang san", new UserServiceImpl());
service.doService();
}
}
输出
静态代理类优缺点
优点:
代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合)
缺点:
1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。如上的代码是只为IUserService类的访问提供了代理,但是如果还要为其他类提供代理的话,就需要我们再次添加代理其他类代理类。
由于静态代理的缺陷,我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理。
三、动态代理
具体用户管理实现类
class UserServiceImpl implements IUserService{
@Override
public void doService() {
// TODO Auto-generated method stub
System.out.println("doing UserServiceImpl.doService");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
代理类–代理用户管理实现类
//创建 实现InvocationHandler接口的类:
class UserServiceHandler implements InvocationHandler{
private IUserService service;
public UserServiceHandler(IUserService service) {
super();
this.service = service;
}
/*
* Java反射的时候invoke 增强的功能在invoke中实现
* Construct : 构造函数的类
*
* Method : 方法的类 Method.invoke(xxxxx)
*
* Field : 描述属性的类
* Object proxy : Proxy库给我们生成的代理对象
* Method method: 代理类需要调用的真正服务类的方法描述
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
long begin = System.currentTimeMillis();
//通过反射机制调用委托类的服务方法
//invoke中的service是真实对象
method.invoke(service, args);
long end = System.currentTimeMillis();
System.out.println("spend time:" + (end-begin) + "ms");
return null;
}
}
客户端调用
public class TestProxyDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles",
"true"); //可以查看jdk生成的动态代理类
IUserService service =
(IUserService)Proxy.newProxyInstance(TestProxyDemo.class.getClassLoader(),
//动态代理的接口 //实现invocationHandeler接口的类(这个类是动态生成的)
new Class<?>[]{IUserService.class}, (InvocationHandler) new UserServiceHandler(new UserServiceImpl()));
service.doService();
}
动态代理优点:
动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强。