前言
代理模式是常用的结构型设计模式之一,当直接访问某些对象存在问题时可以通过一个代理对象来间接的访问,为了保证客户端使用的透明性,所访问的真实对象与代理对象要实现相同的接口。根据代理模式的使用的目的不同,代理模式又可以分为多种类型,如远程代理、虚拟代理、保护代理等,他们应用于不同的场合,满足用户的不同需求。
1、代理模式定义
给一个对象提供一个代理,并由代理对象控制对象的应用。代理模式的英文叫做Proxy或Surrogate,它是一种对象结构模式。
2、代理模式分类
对于代理模式我们可以简单的将其分为两种,及静态代理和动态代理,但是在实际的应用中动态代理使用较静态代理更加广泛。
2.1、静态代理
在静态代理的实现中代理类必须与目标类实现同一个接口,在代理类相关方法中调用目标类的相关方法,使客户端通过代理类间接的访问目标类,可以在代理代理类中添加与业务无关的系统代码,保证了业务代码的纯粹性。符合设计模式的开闭原则。
下面通过简单的例子展示静态代理类的使用,首先是代理类和目标类需要实现的接口:
import java.util.List;
public interface OrderService {
// 创建订单
boolean createOrder();
// 查找订单
List listOrder();
// 删除订单
boolean removeOrder();
}
接口的目标实现类:
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
import com.apesource.service.OrderService;
/*
* 订单业务服务类
*/
public class OrderServiceImpl implements OrderService{
@Override
public boolean createOrder() {
System.out.println("A.创建订单业务步骤1");
System.out.println("B.创建订单业务步骤2");
System.out.println("C.创建订单业务步骤3");
System.out.println("D.创建订单业务步骤4");
System.out.println("E.创建订单业务步骤5");
return true;
}
@Override
public List listOrder() {
System.out.println("A.查找订单业务步骤1");
System.out.println("B.查找订单业务步骤2");
System.out.println("C.查找订单业务步骤3");
return Arrays.asList();
}
@Override
public boolean removeOrder() {
System.out.println("A.删除订单业务步骤1");
System.out.println("B.删除订单业务步骤2");
System.out.println("C.删除订单业务步骤3");
return true;
}
}
代理类(实现添加日志功能):
import java.util.List;
import java.util.logging.Logger;
import com.apesource.service.OrderService;
import com.apesource.service.impl.OrderServiceImpl;
/*
* 代理类
* 在该类中添加日志相关方法可无需改变原有业务代码
*/
public class OrderServiceProxy implements OrderService{
//创建目标类(委托类/被代理类)
OrderServiceImpl targetOrderService;
public OrderServiceProxy() {
//实例化目标类对象(当创建代理对象时)
targetOrderService = new OrderServiceImpl();
}
//创建日志类
private static Logger log = Logger.getLogger(OrderServiceImpl.class.getName());
@Override
public boolean createOrder() {
log.info("开始执行创建定单业务!");
//在代理类中调用目标被代理类的相关方法
boolean isCreat = targetOrderService.createOrder();
log.info("结束执行创建定单业务!");
return isCreat;
}
@Override
public List listOrder() {
log.info("开始执行查询定单业务!");
List orderList = targetOrderService.listOrder();
log.info("结束执行查询定单业务!");
return orderList;
}
@Override
public boolean removeOrder() {
log.info("开始执行删除定单业务!");
boolean isRemove = targetOrderService.removeOrder();
log.info("结束执行删除定单业务!");
return isRemove;
}
}
测试类:
import com.apesource.service.OrderService;
import com.apesource.service.proxy.OrderServiceProxy;
public class test_01 {
public static void main(String[] args) {
OrderService orderService = new OrderServiceProxy();
orderService.createOrder();
}
}
控制台输出结果:
2.2、 动态代理
Java动态代理实现相关类位于java.lang.reflect包,主要涉及两个类:
- InvocationHandler接口。它是代理实例的调用处理程序实现的接口,该接口中定义了如下方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
invoke()方法中的第一个参数proxy表示代理类,第二个参数method表示需要代理的方法,第三个参数args表示代理方法的参数数组。
- Proxy类。该类即为动态代理类,该类最常用的方法为:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
- newProxyInstance()方法。
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException
用于根据传入的接口类型interfaces返回一个动态创建的代理类的实例,方法中第一个参数loader表示代理类的类加载器,第二个参数interfaces表示代理类实现的接口列表(与真实主题类的接口列表一致),第三个参数h表示所指派的调用处理程序类。
下面通过简单的例子展示动态代理类的使用,接口与目标类与静态代理相同,此处不再重复。
下面是实现了InvocationHandler接口的代理类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.logging.Logger;
public class LogInvocationHandler implements InvocationHandler{
//定义目标对象
private Object targetobj;
//定义日志相关组件
private static Logger log = Logger.getLogger(LogInvocationHandler.class.getName());
//定义有参构造方法,用于接收目标对象
public LogInvocationHandler(Object obj) {
this.targetobj=obj;
}
/*
* proxy:运行时的动态代理目标对象
* method:目标对象的方法
* args:目标对象方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行目标方法
log.info("方法开始执行");
Object returnValue = method.invoke(targetobj, args);
log.info("方法执行结束");
return returnValue;
}
}
测试类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import com.apesource.service.OrderService;
import com.apesource.service.impl.OrderServiceImpl;
import com.apesource.service.proxy.LogInvocationHandler;
public class Test01 {
public static void main(String[] args) {
//创建目标对象
OrderService orserservicTarget = new OrderServiceImpl();
//公共系统代码组件(定义代理需要执行的系统代码逻辑,例如:日志处理器)
InvocationHandler logInvocation = new LogInvocationHandler(orserservicTarget);
//创建新的代理实例
OrderService orderServiceProxy = (OrderService)Proxy.newProxyInstance(orserservicTarget.getClass().getClassLoader(), orserservicTarget.getClass().getInterfaces(),logInvocation);
//调用目标类方法
orderServiceProxy.createOrder();
}
}
控制台输出结果:
代理模式的特点
- 代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。
- 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求处理的速度变慢。
- 实现代理模式需要额外的工作,有些代理模式的实现呢非常复杂。
- 在动态代理模式中,对于多个真实主题角色,只需要提供一个动态代理类,在客户端可以通过配置文件设置具体真实主题角色的类名,在动态代理类中无须维护一个与真实主题角色的引用,用户可以根据需要自定义新的真实主题角色,在系统设计和客户端程序实现时也无须关心真实主题角色,系统灵活性可扩展性更好。