zoukankan      html  css  js  c++  java
  • 设计模式课程 设计模式精讲 16-4 代理模式Coding-动态代理

    1    代码演练

    1.1  动态代理

    2    疑难解答

    2.1  动态代理invoke怎么执行的?

    2.2  感觉这块理解的不是很好,下边有时间再看看

    1    代码演练
    1.1  动态代理

    重点:

    重点关注动态代理类

    测试类:

    package com.geely.design.pattern.structural.proxy.dynamicproxy;
    
    import com.geely.design.pattern.structural.proxy.IOrderService;
    import com.geely.design.pattern.structural.proxy.Order;
    import com.geely.design.pattern.structural.proxy.OrderServiceImpl;
    
    public class Test {
        public static void main(String [] args){
            Order order = new Order();
            order.setUserID(1);
            /**
             * new OrderServiceDynamicProxy(order) 该方法已经生成了一个新的代理类
             * 它的bind方法返回了原目标类,强转之后变成了原目标类。
             */
            IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();
            //注意,执行saveOrder方法,最终会执行invode方法。
            orderServiceDynamicProxy.saveOrder(order);
        }
    }

    动态代理类:

    package com.geely.design.pattern.structural.proxy.dynamicproxy;
    
    
    import com.geely.design.pattern.structural.proxy.Order;
    import com.geely.design.pattern.structural.proxy.db.DataSourceContextHolder;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 目的:抽奖信息和订单等不同的类都可以通过这一个动态代理进行复用,不用每一个都写一个静态代理。
     * 这就是静态代理和动态代理的区别
     * 动态代理是自动生成的,静态代理需要显式的来描述和coding
     */
    public class OrderServiceDynamicProxy implements InvocationHandler {
        //目标对象
        public Object target;
    
        //通过构造方法传入目标对象
        public OrderServiceDynamicProxy(Object target) {
            this.target = target;
        }
    
        /**
         * 主方法, 调用前置方法,主要方法,以及后置方法
         * @param proxy
         * @param method
         * @param args
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //取得目标对象,argObject是目标类,也就是静态代理demo中的订单类
            Object argObject = args[0];
            beforeMethod(argObject);
            Object object = method.invoke(target,args);
            afterMethod();
            return object;
        }
    
        public Object bind(){
            //得到目标对象的class类
            Class cls = target.getClass();
            //这里边有三个参数,classLoader,复数的interface,它的类型是class,第三个是invoccationHandler 因为本类本身实现了InvocationHandler,所以把本类自己传过去即可。
            return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),this);
        }
    
        /**
         * 前置方法,用来取模运算
         * @param obj
         */
        private void beforeMethod(Object obj){
            int userID = 0;
            System.out.println("动态代理 before code");
            if(obj instanceof Order){//如果该对象属于Order类
                Order order = (Order) obj;//强转成Order 类
                userID = order.getUserID();
            }
            int dbRouter = userID%2;
            System.out.println("动态代理分配到 【db"+dbRouter+"】数据库进行处理数据!");
            DataSourceContextHolder.setDBType("db"+String.valueOf(dbRouter));
        }
    
        /**
         * 后置方法
         */
        private void afterMethod(){
            System.out.println("动态代理 after code");
        }
    
    }

    订单类:

    package com.geely.design.pattern.structural.proxy;
    
    /**
     * 建立订单实体类
     */
    public class Order {
        private Object orderInfo;
        //之所以选择integer类型,是为了方便OrderServiceStaticProxy静态代理类进行分库
        private Integer userID;
    
        public Object getOrderInfo() {
            return orderInfo;
        }
    
        public void setOrderInfo(Object orderInfo) {
            this.orderInfo = orderInfo;
        }
    
        public Integer getUserID() {
            return userID;
        }
    
        public void setUserID(Integer userID) {
            this.userID = userID;
        }
    }

    订单dao:

    package com.geely.design.pattern.structural.proxy;
    
    public interface IOrderDao {
        int insertOrder(Order order);
    }

    订单daoIMPL:

    package com.geely.design.pattern.structural.proxy;
    
    public class OrderDaoImpl implements IOrderDao{
        @Override
        public int insertOrder(Order order) {
            System.out.println("新增一条订单!");
            return 1;
        }
    }

    订单Service:

    package com.geely.design.pattern.structural.proxy;
    
    public interface IOrderService {
        int saveOrder(Order order);
    }

    订单ServiceIMPL:

    package com.geely.design.pattern.structural.proxy;
    
    public class OrderServiceImpl implements IOrderService {
        private IOrderDao orderDao;
    
        @Override
        public int saveOrder(Order order) {
            //Spring会自己注入,这里我们直接new了
            orderDao = new OrderDaoImpl();
            System.out.println("Service层调用dao层添加Order");
            return orderDao.insertOrder(order);
        }
    }

    打印日志:

    Connected to the target VM, address: '127.0.0.1:12906', transport: 'socket'
    动态代理 before code
    动态代理分配到 【db1】数据库进行处理数据!
    Disconnected from the target VM, address: '127.0.0.1:12906', transport: 'socket'
    Service层调用dao层添加Order
    新增一条订单!
    动态代理 after code
    
    Process finished with exit code 0
    2    疑难解答
    2.1  动态代理invoke怎么执行的?

    1.Proxy.newProxyInstance(//参数省略了...)的部分源码

    2.程序运行时产生一个类$proxyQ
    3.Sproxy0类继承自Proxy类,实现了目标对象的父类接口(借鉴的百度提供的源码

    4.Sproxy0类有多个Method成员变量,它的静态代码块给Method赋值为我们自己的接口的实现类的对应的Method对象
    5.Sproxyo实现接口的方法调用了super.h.invoke(参数),这里的参数包括Method变量

    这样就缕顺了,整体流程:
    代理对象调接口中的方法---代理对象的真身是$proxy0 调用了对应的方法---此方法内部调用其父类的成员h调用h的invoke方法---就是调用传入了InvocationHandler的invoke方法,至于返回值,那就看我们的InvocationHandler的实现类怎么写了。

    这部分参考:https://www.jianshu.com/p/774c65290218

  • 相关阅读:
    YbtOJ:NOIP2020 模拟赛B组 Day10
    洛谷11月月赛Ⅱ-div.2
    P1494 [国家集训队]小Z的袜子
    [模板]莫队/P3901 数列找不同
    P4145 上帝造题的七分钟2 / 花神游历各国
    P4109 [HEOI2015]定价
    P4168 [Violet]蒲公英
    分块
    P3378 【模板】堆(code)
    网络基础——网络层
  • 原文地址:https://www.cnblogs.com/1446358788-qq/p/11563452.html
Copyright © 2011-2022 走看看