代理模式(二)

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();
    }

}
相關文章
相關標籤/搜索