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

 

posted on 2019-09-17 06:33  菜鸟乙  阅读(220)  评论(0编辑  收藏  举报