代理模式详解——静态代理

代理模式的应用场景
在生活中,我们经常见到这样的场景,如:租房中介、售票黄牛、婚介、经纪人、快递、
事务代理、非侵入式日志监听等,这些都是代理模式的实际体现。代理模式(Proxy
Pattern)的定义也非常简单,是指为其他对象提供一种代理,以控制对这个对象的访问。
代理对象在客服端和目标对象之间起到中介作用,代理模式属于结构型设计模式。使用
代理模式主要有两个目的:一保护目标对象,二增强目标对象。下面我们来看一下代理
模式的类结构图:

代理模式详解——静态代理

Subject 是顶层接口,RealSubject 是真实对象(被代理对象),Proxy 是代理对象,代
理对象持有被代理对象的引用,客户端调用代理对象方法,同时也调用被代理对象的方
法,但是在代理对象前后增加一些处理。在代码中,我们想到代理,就会理解为是代码
增强,其实就是在原本逻辑前后增加一些逻辑,而调用者无感知。代理模式属于结构型
模式,有静态代理和动态代理。

静态代理
举个例子:人到了适婚年龄,父母总是迫不及待希望早点抱孙子。而现在社会的人在各
种压力之下,都选择晚婚晚育。于是着急的父母就开始到处为自己的子女相亲,比子女
自己还着急。这个相亲的过程,就是一种我们人人都有份的代理。来看代码实现:
顶层接口Person:

/**
* 人有很多行为,要谈恋爱,要住房子,要购物,要工作
*/
public interface Person {
   public void findLove();

}

儿子要找对象,实现Son 类:
public class Son implements Person{
  public void findLove(){
//我没有时间
    System.out.println("儿子要求:肤白貌美大长腿");
}}
父亲要帮儿子相亲,实现Father 类:

public class Father {
   private Son son;
   //没办法扩展
   public Father(Son son){
     this.son = son;
    }
    //目标对象的引用给拿到
    public void findLove(){
        System.out.println("父母物色对象");
         this.son.findLove();
        System.out.println("双方同意交往,确立关系");
}}

来看测试代码:
public static void main(String[] args) {
   //只能帮儿子找对象
   //不能帮表妹、不能帮陌生人
    Father father = new Father(new Son());
     father.findLove();
}
运行结果:

代理模式详解——静态代理

这里小伙伴们可能会觉得还是不知道如何讲代理模式应用到业务场景中,那么我们再来
举例一个实际的业务场景。在分布式业务场景中,我们通常会对数据库进行分库分表,
分库分表之后使用Java 操作时,就可能需要配置多个数据源,我们通过设置数据源路由
来动态切换数据源。先创建Order 订单实体:

代理模式详解——静态代理

创建OrderDao 持久层操作类:

public class OrderDao {
    public int insert(Order order){

   System.out.println("OrderDao 创建Order 成功!");
   return 1;
}
}

创建IOrderService 接口:
public interface IOrderService {
   int createOrder(Order order);
   }
创建OrderService 实现类:
public class OrderService implements IOrderService {
   private OrderDao orderDao;
   public OrderService(){
   //如果使用Spring 应该是自动注入的
   //我们为了使用方便,在构造方法中将orderDao 直接初始化了
    orderDao = new OrderDao();
    }
@Override
public int createOrder(Order order) {
    System.out.println("OrderService 调用orderDao 创建订单");
  return orderDao.insert(order);
    }
}

接下来使用静态代理,主要完成的功能是,根据订单创建时间自动按年进行分库。根据
开闭原则,原来写好的逻辑我们不去修改,通过代理对象来完成。先创建数据源路由对
象,我们使用ThreadLocal 的单例实现,DynamicDataSourceEntry 类:

package com.gupaoedu.vip.pattern.proxy.staticproxy.dbroute.db;
/**
* 动态切换数据源
* @author Tom
*/
public class DynamicDataSourceEntry {
  private DynamicDataSourceEntry(){}
/**
* 清空数据源
*/
  public static void clear() {
  local.remove();
   }
/**
* 获取当前正在使用的数据源名字
*
* @return String
*/
    public static String get() {
       return local.get();
   }
 /**
* 还原当前切面的数据源
*/
   public static void restore() {
   local.set(DEFAULT_SOURCE);
}// 默认数据源
       public final static String DEFAULT_SOURCE = null;
      private final static ThreadLocal<String> local = new ThreadLocal<String>();

/**
* 设置已知名字的数据源
*
* @param source
*/
    public static void set(String source) {
    local.set(source);
   }
/**
* 根据年份动态设置数据源
* @param year
*/
    public static void set(int year) {
      local.set("DB_" + year);
     }
}

创建切换数据源的代理OrderServiceSaticProxy 类:

package com.gupaoedu.vip.pattern.proxy.staticproxy.dbroute.proxy;
import com.gupaoedu.vip.pattern.proxy.staticproxy.dbroute.IOrderService;
import com.gupaoedu.vip.pattern.proxy.staticproxy.dbroute.Order;
import com.gupaoedu.vip.pattern.proxy.staticproxy.dbroute.db.DynamicDataSourceEntry;
import java.text.SimpleDateFormat;
import java.util.Date;
public class OrderServiceStaticProxy implements IOrderService {
  private SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
   private IOrderService orderService;
   public OrderServiceStaticProxy(IOrderService orderService){
      this.orderService = orderService;
    }
   public int createOrder(Order order) {
    before();
    Long time = order.getCreateTime();
   Integer dbRouter = Integer.valueOf(yearFormat.format(new Date(time)));
   System.out.println("静态代理类自动分配到【DB_" + dbRouter + "】数据源处理数据。");
    DynamicDataSourceEntry.set(dbRouter);
      orderService.createOrder(order);
   after();
    return 0;
}
   private void before(){
   System.out.println("Proxy before method.");
  }
  private void after(){
    System.out.println("Proxy after method.");
    }
}

来看测试代码:
public static void main(String[] args) {

try {
   Order order = new Order();
   // Date today = new Date();
    // order.setCreateTime(today.getTime());
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
    Date date = sdf.parse("2017/02/01");
    order.setCreateTime(date.getTime());
    IOrderService orderService = new OrderServiceStaticProxy(new OrderService());
    orderService.createOrder(order);
    }catch (Exception e){
    e.printStackTrace();;
     }
}

代理模式详解——静态代理

符合我们的预期效果。现在我们再来回顾一下类图,看是不是和我们最先画的类结构一
致:

代理模式详解——静态代理