第十三章 代理模式

快速导航
一、代理模式介绍
二、代码演示
三、jdk中使用代理模式的地方
一、代理模式介绍

定义:为其他对象提供一种代理,以控制对这个对象的访问
代理对象在客户端和目标对象之间起到中介作用

适用场景:
保护目标对象
增强目标对象

优点:
代理模式能将代理对象与真实被调用的目标对象分离
一定程度上降低了系统的耦合度,扩展性好
保护目标对象
增强目标对象

缺点:
造成系统设计中类数量的增加
在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢
增加系统的复杂性

扩展:
静态代理就是在代码中显示指定的代理;
动态代理无法代理类,但是可以代理接口;
CGLib代理:可以代理类

Spring 代理选择:
当Bean有实现接口时,Spring就会用jdk的动态代理;
当Bean没有实现接口时,Spring使用CGLib;
配置 <aop:aspectj-autoproxy proxy-target-class=“true” />,强制使用CGLib

相关设计模式:
代理模式与装饰者模式
代理模式与适配器模式

二、代码演示

1、静态代理模式

//订单类
public class Order {
    private Object OrderInfo;
    private Integer userId;

    public Object getOrderInfo() {
        return OrderInfo;
    }
    public void setOrderInfo(Object orderInfo) {
        OrderInfo = orderInfo;
    }
    public Integer getUserId() {
        return userId;
    }
    public void setUserId(Integer userId) {
        this.userId = userId;
    }
}

//订单处理Dao层
public class OrderDao {
    public int insert(Order order){
        System.out.println("dao层添加order成功");
        return 1;
    }
}
//订单服务层
public class IOrderService {
    public int saveOrder(Order order) {
        /** Spring会自己注入,我们这里就直接new出来了 */
        OrderDao iOrderDao = new OrderDao();
        System.out.println("Service调用Dao层添加Order层");
        return iOrderDao.insert(order);
    }
}
//设置 db 的路由位置
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 CONTEXT_HOLDER.get();
    }
    public static void clearDBType(){
        CONTEXT_HOLDER.remove();
    }
}
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDBType();
    }
}
/**
 * @program: adpn-pattern->StaticOrderServiceProxy
 * @description: 静态代理类
 * @author: Jstar
 * @create: 2019-11-30 15:36
 **/
public class StaticOrderServiceProxy {
    public int saveOrder(Order order){
        beforeMethod();
        /** 在代理类里面注入目标对象,但最终实现还是由目标类来完成的  */
        IOrderService iorderService = new IOrderService();
        Integer userId = order.getUserId();
        /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */
        int dbRouter = userId % 2;
        System.out.println("静态代理分配到 db"+dbRouter+" 处理数据");
        DataSourceContextHolder.setDBType(String.valueOf(dbRouter));
        afterMethod();
        return iorderService.saveOrder(order);
    }

    // 增强的 before 方法
    private void beforeMethod() {
        System.out.println("静态代理 before code");
    }
    // 增强的 after 方法
    private void afterMethod() {
        System.out.println("静态代理 after code");
    }
}
//测试类
public class Test {
    public static void main(String[]args){
        Order order = new Order();
        order.setUserId(10);
        StaticOrderServiceProxy staticOrderServiceProxy = new StaticOrderServiceProxy();
        staticOrderServiceProxy.saveOrder(order);
    }
}

这是类的uml图:
在这里插入图片描述

运行结果:

在这里插入图片描述

2、动态代理模式

我们把部分代码改一下:

//IOrderService  改为接口
public interface IOrderService {
    public int saveOrder(Order order);
}
//IOrderService 接口的实现
public class IOrderServiceImpl implements IOrderService{
    @Override
    public int saveOrder(Order order) {
        /** Spring会自己注入,我们这里就直接new出来了 */
        OrderDao iOrderDao = new OrderDao();
        System.out.println("Service调用Dao层添加Order层");
        return iOrderDao.insert(order);
    }
}
/**
 * @program: adpn-pattern->DynamicOrderProxy
 * @description: 动态代理类
 * @author: Jstar
 * @create: 2019-11-30 15:57
 **/
public class DynamicOrderProxy implements InvocationHandler {
    //这是目标类
    private Object target;
    //通过构造器把目标类注入进来
    public DynamicOrderProxy(Object target) {
        this.target = target;
    }
    //进行绑定
    public Object bind(){
        Class aClass = target.getClass();
        return Proxy.newProxyInstance(aClass.getClassLoader(),aClass.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;
    }

    private void beforeMethod(Object argObject) {
        int userId = 0;
        System.out.println("动态代理before code");
        if (argObject instanceof Order) {
            Order order = (Order) argObject;
            userId = order.getUserId();
        }
        /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */
        int dbRouter = userId % 2;
        System.out.println("动态代理分配到 db"+dbRouter+" 处理数据");
        //todo 设置dataSource;
        DataSourceContextHolder.setDBType(String.valueOf(dbRouter));
    }
    private void afterMethod() {
        System.out.println("动态代理after core");
    }
}
//测试类

public class Test {
    public static void main(String[]args){
        Order order = new Order();
        order.setUserId(10);
        //动态代理
        IOrderService iOrderService = (IOrderService) new DynamicOrderProxy(new IOrderServiceImpl()).bind();
        iOrderService.saveOrder(order);
    }
}

看一下运行结果:
在这里插入图片描述

三、代理模式在jdk中的使用

1、AOP
2、org.springframework.aop.framework.ProxyFactoryBean

在这里插入图片描述

3、org.springframework.aop.framework.CglibAopProxy

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值