代理模式(Proxy Pattern)是指爲其餘對象提供一種代理,以控制對這個對象的訪問。數據庫
代理對象在客戶端和目標對象之間起到中介做用。屬於結構型設計模式設計模式
適用場景: 1 保護目標對象 2 加強目標對象ide
靜態代理: 顯式聲明被代理對象this
缺點: 不符合開閉原則spa
public interface Person { void findLove(); }
public class Son implements Person{ @Override public void findLove(){ System.out.println("兒子要求:膚白貌美大長腿"); } public void findJob(){ } public void eat(){ } }
public class Father implements Person { private Son person; public Father(Son person){ this.person = person; } public void findLove(){ System.out.println("父親物色對象"); this.person.findLove(); System.out.println("雙方父母贊成,確立關係"); } public void findJob(){ } }
public static void main(String[] args) { Father father = new Father(new Son()); father.findLove(); }
//經常使用的一種靜態代理的形式:對數據庫進行分庫分表 ,hreadLocal 進行數據源動態切換設計
public class Order { private Object orderInfo; //訂單建立時間進行按年分庫 private Long createTime; private String id; public Object getOrderInfo() { return orderInfo; } public void setOrderInfo(Object orderInfo) { this.orderInfo = orderInfo; } public Long getCreateTime() { return createTime; } public void setCreateTime(Long createTime) { this.createTime = createTime; } public String getId() { return id; } public void setId(String id) { this.id = id; } }
public class OrderDao { public int insert(Order order){ System.out.println("OrderDao建立Order成功!"); return 1; } }
public interface IOrderService { int createOrder(Order order); }
public class OrderService implements IOrderService { private OrderDao orderDao; public OrderService(){ //若是使用Spring應該是自動注入的 //咱們爲了使用方便,在構造方法中將orderDao直接初始化了 orderDao = new OrderDao(); } public int createOrder(Order order) { System.out.println("OrderService調用orderDao建立訂單"); return orderDao.insert(order); } }
public class DynamicDataSourceEntity { // 默認數據源 public final static String DEFAULT_SOURCE = null; private final static ThreadLocal<String> local = new ThreadLocal<String>(); private DynamicDataSourceEntity(){} /** * 清空數據源 */ public static void clear() { local.remove(); } /** * 獲取當前正在使用的數據源名字 */ public static String get(){return local.get();} /** * 還原當前切面的數據源 */ public static void restore(){ local.set(DEFAULT_SOURCE); } /** * 設置已知名字的數據源 * @param source */ public static void set(String source){local.set(source);} /** * 根據年份動態設置數據源 * @param year */ public static void set(int year){local.set("DB_" + year);} }
public class OrderServiceStaticProxy implements IOrderService { private SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy"); private IOrderService orderService; public OrderServiceStaticProxy(IOrderService orderService) { this.orderService = orderService; } @Override public int createOrder(Order order) { Long time = order.getCreateTime(); Integer dbRouter = Integer.valueOf(yearFormat.format(new Date(time))); System.out.println("靜態代理類自動分配到【DB_" + dbRouter + "】數據源處理數據" ); DynamicDataSourceEntity.set(dbRouter); this.orderService.createOrder(order); DynamicDataSourceEntity.restore(); return 0; } }
public static void main(String[] args) { try { Order order = new Order(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); Date date = sdf.parse("2019/04/02"); order.setCreateTime(date.getTime()); IOrderService orderService = new OrderServiceStaticProxy(new OrderService()); orderService.createOrder(order); }catch (Exception e){ e.printStackTrace(); } }
動態代理: 動態配置和替換被代理對象代理
JDK動態代理的實現原理:rest
1 拿到被代理類的引用,而且獲取它的全部的接口(反射獲取)orm
2 JDK Proxy類從新生成一個新的類,實現了被代理類全部接口的方法對象
3 動態生成Java代碼,把加強邏輯加入到新生成代碼中
4 編譯生成新的Java代碼的class文件
5 加載並從新運行新的class,獲得類就是全新類
public interface Person { void findLove(); }
public class Girl implements Person { public void findLove() { System.out.println("高富帥"); System.out.println("身高180cm"); System.out.println("有6塊腹肌"); } }
public class JDKMeipo implements InvocationHandler { private Object target; public Object getInstance(Object target) throws Exception{ this.target = target; Class<?> clazz = target.getClass(); return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this); } 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("OK的話,準備辦事"); } }
public static void main(String[] args) { try { Object obj = new JDKMeipo().getInstance(new Girl()); Method method = obj.getClass().getMethod("findLove", null); method.invoke(obj); } catch (Exception e) { e.printStackTrace(); } }
JVM在class文件定義時,規定interface的類型是u2,2個字節,16位,那麼最多支持2的16次方-1,也就是65535