JDK動態代理框架
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 OrderServiceDynamicProxy implements InvocationHandler { private SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy"); Object proxyObj; public Object getInstance(Object proxyObj) { this.proxyObj = proxyObj; Class<?> clazz = proxyObj.getClass(); return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(args[0]); Object object = method.invoke(proxyObj,args); after(); return object; } private void after() { System.out.println("Proxy after method"); //還原成默認的數據源 DynamicDataSourceEntity.restore(); } //target 應該是訂單對象Order private 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(time))); System.out.println("靜態代理類自動分配到【DB_" + dbRouter + "】數據源處理數據"); DynamicDataSourceEntity.set(dbRouter); }catch (Exception e){ e.printStackTrace(); } } }
public static void main(String[] args) { try { Order order = new Order(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); Date date = sdf.parse("2019/04/05"); order.setCreateTime(date.getTime()); IOrderService orderService = (IOrderService)new OrderServiceDynamicProxy().getInstance(new OrderService()); orderService.createOrder(order); }catch (Exception e){ e.printStackTrace(); } }
CGLib動態代理容易踩的坑:工具
1 沒法代理final修飾的方法this
CGLib和JDK動態代理對比:設計
1 JDK動態代理是實現了被代理對象的接口,CGLib是繼承了被代理對象代理
2 JDK和CGLib都是在運行期生成字節碼,JDK是直接寫Class字節碼,CGLib使用ASM框架寫Class字節碼,Cglib代理實現更復雜,生成代理類比JDK效率低。rest
3 JDK調用代理方法,是經過反射機制調用,CGLib是經過FastClass機制直接調用方法,CGLib執行效率更高orm
優勢:對象
1 代理模式能將代理對象與真實被調用的目標對象分離繼承
2 必定程度上下降了系統的耦合程度,易於擴展接口
3 代理能夠起到保護目標對象的做用
4 加強目標對象的職責
缺點:
1 代理模式會形成系統設計中類的數目增長
2 在客戶端和目標對象之間增長了一個代理對象,會形成請求處理速度變慢
3 增長了系統的複雜度
Spring中的代理選擇原則:
1 當Bean有實現接口時,Spring就會用JDK的動態代理
2 當Bean沒有實現接口時,Spring選擇CGLib
3 Spring能夠經過配置強制使用CGLib,只需在Spring的配置文件中加入以下代碼: <aop:aspectj-autoproxy proxy-target-class="true"/>
public class Customer { public void findLove(){ System.out.println("兒子要求:膚白貌美大長腿"); } }
public class CGlibMeipo implements MethodInterceptor { public Object getInstance(Class<?> clazz) throws Exception{ //至關於Proxy,代理的工具類 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { before(); Object obj = methodProxy.invokeSuper(o,objects); 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 { //JDK是採用讀取接口的信息 //CGLib覆蓋父類方法 //目的:都是生成一個新的類,去實現加強代碼邏輯的功能 //JDK Proxy 對於用戶而言,必需要有一個接口實現,目標類相對來講複雜 //CGLib 能夠代理任意一個普通的類,沒有任何要求 //CGLib 生成代理邏輯更復雜,效率,調用效率更高,生成一個包含了全部的邏輯的FastClass,再也不須要反射調用 //JDK Proxy生成代理的邏輯簡單,執行效率相對要低,每次都要反射動態調用 //CGLib 有個坑,CGLib不能代理final的方法 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E://cp_classes"); Customer obj = (Customer) new CGlibMeipo().getInstance(Customer.class); System.out.println(obj); obj.findLove(); } catch (Exception e) { e.printStackTrace(); } }