动态代理和静态代理的基本思路是一致的,只不过动态代理的功能更加强大,随着业务的扩展适应更强大。如果还以找对象为例,那么使用动态代理相当于能够适应复杂的业务场景。不仅包括父亲给儿子找对象,如果找对象这项业务发展成了一个产业,出现了媒婆、婚介所等,那么用静态代理成本太高了,需要一个更加通用的解决方案,满足任何单身人士找对象的需求。
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() 方法。因为路由规则是根据时间来运算的。我们可以通过接口规范来达到约束的目的。