zoukankan      html  css  js  c++  java
  • 设计模式课程 设计模式精讲 16-2,3 代理模式Coding-静态代理-1

    https://coding.imooc.com/lesson/270.html#mid=18123

    1    代码演练

    1.1  代码演练1(静态代理之分库操作)

    1    代码演练
    1.1  代码演练1(静态代理之分库操作)

    需求:

    订单管理,模拟前置后置方法,模拟分库管理

    重点:

    重点看订单静态代理,动态数据源和分库操作上下文。

    UML类图:

    测试类:

    package com.geely.design.pattern.structural.proxy;
    
    import com.geely.design.pattern.structural.proxy.staticProxy.OrderServiceStaticProxy;
    
    public class Test {
    
        public static void main(String [] args){
            Order order = new Order();
            order.setUserID(1);
            OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy();
            orderServiceStaticProxy.saveOrder(order);
    
            order.setUserID(2);
            orderServiceStaticProxy.saveOrder(order);
    
        }
    }

    订单类:

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

    订单静态代理:

    package com.geely.design.pattern.structural.proxy.staticProxy;
    
    import com.geely.design.pattern.structural.proxy.IOrderService;
    import com.geely.design.pattern.structural.proxy.Order;
    import com.geely.design.pattern.structural.proxy.OrderServiceImpl;
    import com.geely.design.pattern.structural.proxy.db.DataSourceContextHolder;
    
    public class OrderServiceStaticProxy {
        private IOrderService orderService;
    
        /**
         * 添加前置方法和后置方法
         * @param order
         * @return
         */
        public int saveOrder(Order order){
            beforeMethod();
            //spring中会注入,这里我new一下
            orderService = new OrderServiceImpl();
    
            /**
             * 这里添加分库方法,根据user取模,根据余数进行分库
             */
            int userID = order.getUserID();
            int dbRouter = userID%2;
    
            //todo设置datasource,记住,dbType一定要和我们xml中配置的key相同
            DataSourceContextHolder.setDBType("db"+String.valueOf(dbRouter));
    
            System.out.println("静态代理分配到 【db"+dbRouter+"】数据库进行处理数据!");
            int a = orderService.saveOrder(order);
            afterMethod();
            return a;
        }
        /**
         * 这里参照spring aop的做法,增加了前置通知方法  方法的增强
         */
        private void beforeMethod(){
            System.out.println("静态代理  前置方法");
        }
    
        /**
         * 这里参照spring aop的做法,增加了后置通知方法  方法的增强
         */
        private void afterMethod(){
            System.out.println("静态代理  后置方法");
        }
    }

    动态数据源:

    package com.geely.design.pattern.structural.proxy.db;
    
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    /**
     * 分库操作:该类为动态数据源类
     */
    public class DynamicDataSource extends AbstractRoutingDataSource {
        @Override
        protected Object determineCurrentLookupKey() {
            return DataSourceContextHolder.getDBType();
        }
    
        /**
         *  如果是在spring中开发,ioc.xml中
         */
    //    <bean id="db0" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    //        <property name="driverClassName" value="${db.driverClassName}"/>
    //        <property name="url" value="${db.url}"/>
    //        <property name="username" value="${db.username}"/>
    //        <property name="password" value="${db.password}"/>
    //        <!-- 连接池启动时的初始值 -->
    //        <property name="initialSize" value="${db.initialSize}"/>
    //        <!-- 连接池的最大值 -->
    //        <property name="maxActive" value="${db.maxActive}"/>
    //        <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
    //        <property name="maxIdle" value="${db.maxIdle}"/>
    //        <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
    //        <property name="minIdle" value="${db.minIdle}"/>
    //        <!-- 最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制 -->
    //        <property name="maxWait" value="${db.maxWait}"/>
    //        <!--#给出一条简单的sql语句进行验证 -->
    //         <!--<property name="validationQuery" value="select getdate()" />-->
    //        <property name="defaultAutoCommit" value="${db.defaultAutoCommit}"/>
    //        <!-- 回收被遗弃的(一般是忘了释放的)数据库连接到连接池中 -->
    //         <!--<property name="removeAbandoned" value="true" />-->
    //        <!-- 数据库连接过多长时间不用将被视为被遗弃而收回连接池中 -->
    //         <!--<property name="removeAbandonedTimeout" value="120" />-->
    //        <!-- #连接的超时时间,默认为半小时。 -->
    //        <property name="minEvictableIdleTimeMillis" value="${db.minEvictableIdleTimeMillis}"/>
    //
    //        <!--# 失效检查线程运行时间间隔,要小于MySQL默认-->
    //        <property name="timeBetweenEvictionRunsMillis" value="40000"/>
    //        <!--# 检查连接是否有效-->
    //        <property name="testWhileIdle" value="true"/>
    //        <!--# 检查连接有效性的SQL语句-->
    //        <property name="validationQuery" value="SELECT 1 FROM dual"/>
    //    </bean>
    
    
    
    //    <bean id="db1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    //        <property name="driverClassName" value="${db.driverClassName}"/>
    //        <property name="url" value="${db.url}"/>
    //        <property name="username" value="${db.username}"/>
    //        <property name="password" value="${db.password}"/>
    //        <!-- 连接池启动时的初始值 -->
    //        <property name="initialSize" value="${db.initialSize}"/>
    //        <!-- 连接池的最大值 -->
    //        <property name="maxActive" value="${db.maxActive}"/>
    //        <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
    //        <property name="maxIdle" value="${db.maxIdle}"/>
    //        <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
    //        <property name="minIdle" value="${db.minIdle}"/>
    //        <!-- 最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制 -->
    //        <property name="maxWait" value="${db.maxWait}"/>
    //        <!--#给出一条简单的sql语句进行验证 -->
    //         <!--<property name="validationQuery" value="select getdate()" />-->
    //        <property name="defaultAutoCommit" value="${db.defaultAutoCommit}"/>
    //        <!-- 回收被遗弃的(一般是忘了释放的)数据库连接到连接池中 -->
    //         <!--<property name="removeAbandoned" value="true" />-->
    //        <!-- 数据库连接过多长时间不用将被视为被遗弃而收回连接池中 -->
    //         <!--<property name="removeAbandonedTimeout" value="120" />-->
    //        <!-- #连接的超时时间,默认为半小时。 -->
    //        <property name="minEvictableIdleTimeMillis" value="${db.minEvictableIdleTimeMillis}"/>
    //
    //        <!--# 失效检查线程运行时间间隔,要小于MySQL默认-->
    //        <property name="timeBetweenEvictionRunsMillis" value="40000"/>
    //        <!--# 检查连接是否有效-->
    //        <property name="testWhileIdle" value="true"/>
    //        <!--# 检查连接有效性的SQL语句-->
    //        <property name="validationQuery" value="SELECT 1 FROM dual"/>
    //    </bean>
    
    
        /**
         * 这个是在spring中的db的具体的配置
         *
         * 如果我们不指定,默认的是db0beanId
         */
    //    <bean id="dataSource" class="com.geely.design.pattern.structural.proxy.db.DynamicDataSource">
    //        <property name="targetDataSources">
    //            <map key-type="java.lang.String">
    //                <entry value-ref="db0" key="db0"></entry>
    //                <entry value-ref="db1" key="db1"></entry>
    //            </map>
    //        </property>
    //        <property name="defaultTargetDataSource" ref="db0"></property>
    //    </bean>
    
    
    //    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    //        <property name="dataSource" ref="dataSource" />
    //    </bean>
    }

    分库操作上下文:

    package com.geely.design.pattern.structural.proxy.db;
    
    /**
     * 分库操作:
     * dbRouter上下文类 ,在执行dao层之前,如果我们设置了 setDBType设置了dbType为db1 或者 db0,dao层就会去连接对应的数据库。
     * db0和db1就是Spring容器中我们配置的beanID
     */
    public class DataSourceContextHolder {
        //该变量可以存放dataSource的beanName
        private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<String>();
    
        public static void setDBType(String dbType){
            CONTEXT_HOLDER.set(dbType);
        }
    
        public static void clearDBType(String dbType){
            CONTEXT_HOLDER.remove();
        }
    
        public static String getDBType(){
            return (String) CONTEXT_HOLDER.get();
        }
    }

    打印结果:

    Connected to the target VM, address: '127.0.0.1:8341', transport: 'socket'
    静态代理  前置方法
    静态代理分配到 【db1】数据库进行处理数据!
    Service层调用dao层添加Order
    新增一条订单!
    静态代理  后置方法
    静态代理  前置方法
    静态代理分配到 【db0】数据库进行处理数据!
    Service层调用dao层添加Order
    新增一条订单!
    静态代理  后置方法
    Disconnected from the target VM, address: '127.0.0.1:8341', transport: 'socket'
    
    Process finished with exit code 0
  • 相关阅读:
    APP开发的模式
    微信小程序的传值方式
    面试题总结
    github上传文件的步骤
    python使用笔记15--操作Excel
    python使用笔记14--商品管理小练习
    python使用笔记13--清理日志小练习
    python使用笔记12--操作mysql数据库
    python使用笔记11--时间模块
    python使用笔记10--os,sy模块
  • 原文地址:https://www.cnblogs.com/1446358788-qq/p/11531312.html
Copyright © 2011-2022 走看看