代理模式
16-1 代理模式讲解
可以理解为房东和中介的关系:
静态代理就是在代码中显示指定的代理;
动态代理无法代理类,但是可以代理接口;
在使用CGLib代理的时候,因为要用到继承,还有重写,所以对final的这个关键字的时候一定要格外的注意:
16-2 代理模式coding-静态代理-1
这里引入的就是分库的一个业务场景:
- 首先有一个订单类:
public class Order {
private Object orderInfo;
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层的接口:
public interface IOrderDao {
int insert(Order order);
}
- Dao层的实现:
public class OrderDaoImpl implements IOrderDao {
@Override
public int insert(Order order) {
System.out.println("Dao层添加order成功");
return 1;
}
}
- Service层的接口:
public interface IOrderService {
/** 保存订单,参数为订单对象,返回值为生效行数 */
int saveOrder(Order order);
}
- Service层的实现:
public class OrderServiceImpl implements IOrderService {
private IOrderDao iOrderDao;
@Override
public int saveOrder(Order order) {
/** Spring会自己注入,我们这里就直接new出来了 */
iOrderDao = new OrderDaoImpl();
System.out.println("Service调用Dao层添加Order层");
return iOrderDao.insert(order);
}
}
有一个ThreadLocal:
public class DataSourceContextHolder {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
public static void setDBType(String dbType) {
CONTEXT_HOLDER.set(dbType);
}
public static String getDBType() {
return (String)CONTEXT_HOLDER.get();
}
public static void clearDBType() {
CONTEXT_HOLDER.remove();
}
}
Spring里面的分库:
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDBType();
}
}
还有一个静态代理类:
public class OrderServiceStaticProxy {
/** 在代理类里面注入目标对象 */
private IOrderService iOrderService;
/** 我们要在这静态代理类里面增强这个方法 */
public int saveOrder(Order order){
beforeMethod();
/** 如果这里有spring容器的话,就不用显示的new了 */
iOrderService = new OrderServiceImpl();
int userId = order.getUserId();
/** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */
int dbRouter = userId % 2;
System.out.println("静态代理分配到【db"+dbRouter+"】处理数据");
//todo 设置dataSource;
DataSourceContextHolder.setDBType(String.valueOf(dbRouter));
afterMethod();
return iOrderService.saveOrder(order);
}
/** 我们要增强,我们就来写上一个before和after */
private void beforeMethod(){
System.out.println("静态代理 before code");
}
private void afterMethod(){
System.out.println("静态代理 after code");
}
}
16-3 代理模式coding-静态代理-2
测试代码如下:
public class Test {
public static void main(String[]args){
Order order = new Order();
order.setUserId(1);
/** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */
OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy();
orderServiceStaticProxy.saveOrder(order);
}
}
执行结果:
静态代理 before code
静态代理分配到【db1】处理数据
静态代理 after code
Service调用Dao层添加Order层
Dao层添加order成功
当我们把id改成2的时候:
public class Test {
public static void main(String[]args){
Order order = new Order();
order.setUserId(2);
/** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */
OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy();
orderServiceStaticProxy.saveOrder(order);
}
}
执行结果如下:
静态代理 before code
静态代理分配到【db0】处理数据
静态代理 after code
Service调用Dao层添加Order层
Dao层添加order成功
和我们的预期是一样的,这就实现了一个分库的功能;
16-4 代理模式coding-动态代理
这个就是一个动态代理的类:
public class OrderServiceDynamicProxy implements InvocationHandler {
/** 这是目标类 */
private Object target;
/** 通过构造器把目标类注入进来 */
public OrderServiceDynamicProxy(Object target) {
this.target = target;
}
/** 进行绑定 */
public Object bind() {
Class cls = target.getClass();
return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object argObject = args[0];
beforeMethod(argObject);
Object object = method.invoke(target, args);
afterMethod();
return object;
}
public void beforeMethod(Object obj) {
int userId = 0;
System.out.println("动态代理before code");
if (obj instanceof Order) {
Order order = (Order) obj;
userId = order.getUserId();
}
/** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */
int dbRouter = userId % 2;
System.out.println("动态代理分配到【db"+dbRouter+"】处理数据");
//todo 设置dataSource;
DataSourceContextHolder.setDBType(String.valueOf(dbRouter));
}
public void afterMethod() {
System.out.println("动态代理after core");
}
}
我们来写一个测试类:
public class Test {
public static void main(String[]args){
Order order = new Order();
order.setUserId(2);
/** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */
IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();
orderServiceDynamicProxy.saveOrder(order);
}
}
执行结果:
动态代理before code
动态代理分配到【db0】处理数据
Service调用Dao层添加Order层
Dao层添加order成功
动态代理after core
而当我们把id改成1的时候:
public class Test {
public static void main(String[]args){
Order order = new Order();
order.setUserId(1);
/** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */
IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();
orderServiceDynamicProxy.saveOrder(order);
}
}
分到了db1的这个库里面:
执行结果:
动态代理before code
动态代理分配到【db1】处理数据
Service调用Dao层添加Order层
Dao层添加order成功
动态代理after core