打赏
Fork me on GitHub

代理模式-2(动态代理)

  动态代理和静态代理的基本思路是一致的,只不过动态代理的功能更加强大,随着业务的扩展适应更强大。如果还以找对象为例,那么使用动态代理相当于能够适应复杂的业务场景。不仅包括父亲给儿子找对象,如果找对象这项业务发展成了一个产业,出现了媒婆、婚介所等,那么用静态代理成本太高了,需要一个更加通用的解决方案,满足任何单身人士找对象的需求。

  1.JDK 实现方式

  创建媒婆(婚介所)类 JDKMeipo:

package com.xq.design.proxy.dynamicproxy.jdkproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.rmi.server.ExportException;

public class JDKMeipo implements InvocationHandler {
    //被代理 的对象,把引用保存下来
    private Object target;
    public Object getInstance(Object target) throws ExportException {
        this.target = target;
        Class<?> clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object obj = method.invoke(this.target,args);
        after();
        return obj;
    }
    private void before(){
        System.out.println("我是媒婆:我要给你找对象,现在已经确认你的需求");
        System.out.println("开始物色");
    }
    private void after(){
        System.out.println("如果合适的话,就准备办事吧");
    }
}

  创建单身客户类 Customer:

  

public class Customer implements Person {
    @Override
    public void findLove() {
        System.out.println("高富帅");
        System.out.println("身高170");
        System.out.println("我有12块腹肌");
    }
}

  测试代码如下:

  

    @Test
    void test(){
        try{
            Person obj = (Person) new JDKMeipo().getInstance(new Customer());
            obj.findLove();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

  测试结果如下:

  动态代理实现 数据源动态路由业务。 创建动态代理类 OrderServiceDynamicProxy:

package com.xq.design.proxy.dynamicproxy.jdkproxy;

import com.xq.design.proxy.staticproxy.dbroute.db.DynamicDataSourceEntry;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.SimpleDateFormat;
import java.util.Date;

public class OrderServiceDynamicProxy implements InvocationHandler {
    private SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
    private Object target;
    public Object getInstance(Object target){
        this.target = target;
        Class<?> clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
     }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before(args[0]);
        Object object = method.invoke(target, args);
        after();
        return object;
    }
    public void before(Object target){
        try{
            System.out.println("Proxy before method.");
            Long time = (Long) target.getClass().getMethod("getCreateTime").invoke(target);
            Integer dbRouter = Integer.valueOf(yearFormat.format(new Date()));
            System.out.println("动态代理类自动分配到【DB_" + dbRouter + "】数据源处理数据");
            DynamicDataSourceEntry.set(dbRouter);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    private void after(){
        System.out.println("Proxy after method.");
    }
}

  测试代码如下:

    @Test
    void test(){
        try{
            Order order = new Order();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
            Date date = sdf.parse("2020/05/10");
            order.setCreateTime(date.getTime());
            IOrderService orderService = (IOrderService)new OrderServiceDynamicProxy().getInstance(new OrderService());
            orderService.createOrder(order);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

  测试结果如下:

  依然能够达到相同运行效果。但是,使用动态代理实现之后,我们不仅能实现 Order 的数据源冬天路由,还可以实现其他任何类的数据源路由。当然,有个比较重要的约定,必须实现 getCreateTiem() 方法。因为路由规则是根据时间来运算的。我们可以通过接口规范来达到约束的目的。

posted @ 2020-05-10 23:28  l-coil  阅读(175)  评论(0编辑  收藏  举报