代理模式
代理模式属于结构型设计模式,主要是为了能够在不改变原始类代码的情况下,通过引入代理类来给原始类添加功能,代理模式应该是我们非常熟悉的一种设计模式,一般又可以分为静态代理和动态代理,静态代理指的是代理类在编译器就完成了代理功能,而动态代理则是在运行期动态生成的,最熟悉的SpringAOP,面向切面编程,使用的就是动态代理模式,可以动态的增加事务、日志、缓存等功能。
静态代理实例
为原方法添加访问统计功能
public interface OrderService {
void createOrder();
}
public class OrderServiceImpl implements OrderService {
@Override
public void createOrder() {
System.out.println("创建订单");
}
}
public class OrderServiceProxy implements OrderService {
private OrderServiceImpl orderService;
static Map<String, Integer> count = new ConcurrentHashMap<>();
public OrderServiceProxy() {
orderService = new OrderServiceImpl();
}
@Override
public void createOrder() {
count.put("create_order_req_count", count.getOrDefault("create_order_req_count", 0) + 1);
orderService.createOrder();
}
public int getCreateOrderReqCount() {
return count.getOrDefault("create_order_req_count", 0);
}
}
public class OrderTest {
public static void main(String[] args) {
OrderServiceProxy os = new OrderServiceProxy();
os.createOrder();
os.createOrder();
int createOrderReqCount = os.getCreateOrderReqCount();
System.out.println(createOrderReqCount);
}
}
动态代理
在代理业务很少的情况下可以直接使用静态代理来实现,但是如果代理类很多,我们就要把所有的业务接口都实现一遍,添加重复的功能,这显然太麻烦了,要解决这个问题,就可以使用动态代理了,通过在运行时动态的创建代理类,避免了代理类的代码编写。
JDK动态代理
public interface OrderService {
void createOrder();
void queryOrder();
}
public class OrderServiceImpl implements OrderService {
@Override
public void createOrder() {
System.out.println("创建订单");
}
@Override
public void queryOrder() {
System.out.println("查看订单");
}
}
public class OrderServiceDynamicProxy implements InvocationHandler {
private OrderService orderService;
static Map<String, Integer> count = new ConcurrentHashMap<>();
public OrderServiceDynamicProxy(OrderService orderService) {
this.orderService = orderService;
}
public int getCreateOrderReqCount() {
return count.getOrDefault("createOrder_req_count", 0);
}
public int getQueryOrderReqCount() {
return count.getOrDefault("queryOrder_req_count", 0);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
count.put(method.getName() + "_req_count", count.getOrDefault(method.getName() + "_req_count", 0) + 1);
return method.invoke(orderService, args);
}
}
public class OrderTest {
public static void main(String[] args) {
OrderService orderService = new OrderServiceImpl();
OrderServiceDynamicProxy invocationHandler = new OrderServiceDynamicProxy(orderService);
OrderService newProxyInstance = (OrderService) Proxy.newProxyInstance(invocationHandler.getClass().getClassLoader(),
orderService.getClass().getInterfaces(),
invocationHandler);
newProxyInstance.createOrder();
newProxyInstance.createOrder();
newProxyInstance.queryOrder();
newProxyInstance.queryOrder();
newProxyInstance.queryOrder();
System.out.println("创建订单:" + invocationHandler.getCreateOrderReqCount() + "次,查看订单:" + invocationHandler.getQueryOrderReqCount() + "次");
}
}
代理模式的实际应用场景
1、SpringAOP
SpringAOP都应该很熟悉了,底层实际上就是通过动态代理来实现的。
2、MyBatis
MyBatis最经典的使用方式就是直接使用接口方法,这实际上也是通过动态代理实现的。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] {
mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
3、RPC
RPC最经典的口号就是像调用本地方法一样调用远程方法,RPC框架把嗲用远程方法的细节都封装了起来,实际上也是一种代理模式的思想。