浅谈代理模式

一. 静态代理

代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。 代理模式说白了就是“真实对象”的代表,在访问对象时引入一定程度的间接性,因为这种间接性可以附加多种用途。
生活中,代理无处不在:
1、代理销售
2、代理记账
3、代理找对象(百合网、珍爱网)
4、代理找房子(中介)
我们假设出一种场景:
操作员查询销售订单的功能,为了提高查询性能,我们接入缓存功能,如果缓存中有数据,那么直接返回 缓存中的数据,如果缓存中没有数据,那么查询订单数据后,把数据加入到缓存,这样在下次查询订单 数据时,就可以从缓存中读取了。
那我们应该如何来设计这个功能的代码结构呢?
在这里插入图片描述
静态代理类的需要:

  • 实现代理业务的接口
  • 绑定一个具体的被代理对象
  • 接口业务方法中,实现代理对象要完成的具体的事情
public class Order {

   private int oid;
   private String orderInfo;
   private float total;
   private String orderDate;

   public Order() {
   }

   public Order(int oid, String orderInfo, float total, String orderDate) {
       this.oid = oid;
       this.orderInfo = orderInfo;
       this.total = total;
       this.orderDate = orderDate;
   }

   @Override
   public String toString() {
       return "Order{" +
               "oid=" + oid +
               ", orderInfo='" + orderInfo + '\'' +
               ", total=" + total +
               ", orderDate='" + orderDate + '\'' +
               '}';
   }

   public int getOid() {
       return oid;
   }

   public void setOid(int oid) {
       this.oid = oid;
   }

   public String getOrderInfo() {
       return orderInfo;
   }

   public void setOrderInfo(String orderInfo) {
       this.orderInfo = orderInfo;
   }

   public float getTotal() {
       return total;
   }

   public void setTotal(float total) {
       this.total = total;
   }

   public String getOrderDate() {
       return orderDate;
   }

   public void setOrderDate(String orderDate) {
       this.orderDate = orderDate;
   }
}

public class DB {
    private static List<Order> list = new ArrayList<>();
    static {
        list.add(new Order(1,"毛巾3条",45,"2020-2-1"));
        list.add(new Order(2,"小纸巾10包",12,"2020-1-21"));
        list.add(new Order(3,"洗发水1瓶",32,"2020-1-30"));
        list.add(new Order(4,"红牛1箱",36,"2020-2-2"));
        list.add(new Order(5,"哈脾2箱",120,"2020-2-3"));
    }

    public Order getOrder(int oid){
        System.out.println("从数据库中查找数据...");
        for (Order order:list){
            if (order.getOid()==oid) {
                return order;
            }
        }
        return null;
    }
}
public class Cache {

    private Cache(){};
    private Map<Integer, Order> map = new HashMap<>();
    private volatile static Cache cache;

    public static Cache getInstance(){
        if (cache == null) {
            synchronized (Cache.class){
                if (cache == null) {
                    cache = new Cache();
                }
            }
        }
        return cache;
    }



    //把订单添加到缓存中
    public void putCache(int key,Order value){
        System.out.println("把订单数据添加到缓存中.");
        map.put(key,value);
    }
    //从缓存中获取订单
    public Order getCache(int key){
        System.out.println("从缓存中查询订单数据...");
        return map.get(key);
    }
}

public interface OrderDao {
    public Order queryOrder(int oid);
}

public class OrderDaoImpl implements OrderDao {
    DB db=new DB();
    @Override
    public Order queryOrder(int oid) {
        Order order = db.getOrder(oid);
        return order;
    }
}

public class OrderProxy implements OrderDao{

    private OrderDao target;//被代理对象

    public OrderProxy(OrderDao target){
        this.target = target;
    }

    //用于实现目标对象的控制
    //先从缓存中取数据,如果缓存中有,直接返回,如果缓存中没有,那么去数据库取数据,再把数据存入缓存
    @Override
    public Order queryOrder(int oid) {
        Cache cache = Cache.getInstance();
        Order order = cache.getCache(oid); //从缓存中查询订单
        if (null==order) {
            order = target.queryOrder(oid);// 从数据库中查询订单
            cache.putCache(order.getOid(),order); //把订单放入缓存中
        }
        return order;
    }
}

public class Test {
    public static void main(String[] args) {
        OrderDao dao = new OrderDaoImpl();
        Order order = dao.queryOrder(2);
        System.out.println(order);
        System.out.println("-------------");


        //查缓存
        OrderProxy proxy = new OrderProxy(dao);
        Order order1 = proxy.queryOrder(2);
        System.out.println(order1);


        System.out.println("------第二次查询------");
        Order order2 = proxy.queryOrder(2);
        System.out.println(order2);
    }
}

在这里插入图片描述
注意:在第二次查询时,由于缓存区已经存在数据,所以我们是直接从缓存区中获取数据,并不是从DB(伪数据库)中获取数据。

二. 动态代理

动态代理: 顾名思义代理对象的类是通过动态方式来自动生成的,这样的好处是,我们不需要每次为被代理对象单独创建代理类,JDK API 中,对动态代理模式提供了支持
现在我们使用动态代理改进操作员查询销售订单功能

//InvocationHandler 接口用来实现 代理对象要处理的事情
public class CreateProxyFactory implements InvocationHandler {

    private Object target;//被代理对象

    //创建代理对象的方法
    public Object create(Object target){
        this.target = target;
        //JDK 提供动态创建代理类对象的方法(代理对象类加载器,代理对象的接口集合,InvocationHandler(代理对象的处理器))
        Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this);
        return proxy;
    }

    /**
     * //生成的代理对象要执行的代理业务方法
     * @param proxy 代理类对象
     * @param method 被代理对象的方法
     * @param args 被代理对象方法的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Order order = null;
        if (args != null) {
            int oid = (int)args[0];
            order = Cache.getInstance().getCache(oid);
            if (null == order){
                //调用真实的业务方法
                order = (Order)method.invoke(target, args);
                Cache.getInstance().putCache(order.getOid(),order);
            }
        }
        return order;
    }
}

public class TestDy {
    public static void main(String[] args) {
        OrderDao dao = new OrderDaoImpl();
        CreateProxyFactory createProxyFactory = new CreateProxyFactory();
        OrderDao proxy = (OrderDao) createProxyFactory.create(dao);
        Order order = proxy.queryOrder(3);
        System.out.println(order);
        System.out.println("------第二次查询-------");
        Order order1 = proxy.queryOrder(3);
        System.out.println(order1);
    }
}

在这里插入图片描述

三. CGLIB实现动态代理

CGLIB是高性能的代码生成包。可以为没有实现接口的类提供代理,JDK动态代理必须要有接口的补充。 通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。
通过 IDEA添加 CGLIB 包 项目 -> Open Module Settings -> Libraries -> 中间栏的 + 号-> From Maven -> 在输入框输入 cglib -> 等待下拉列表出现 后->选择cglib:cglib:3.3.0
也可以直接用lib导入jar包。
在这里插入图片描述

public class CglibProxy implements MethodInterceptor {
    private Object target;

    public Object create(Object target){
        this.target = target;
        Enhancer enhancer = new Enhancer(); //生成代理对象的增强类(工具类)
        enhancer.setSuperclass(this.target.getClass());//设置代理类的父类
        enhancer.setCallback(this);//设置代理类的处理方法
        enhancer.setClassLoader(this.target.getClass().getClassLoader());//设置类加载器
        Object obj = enhancer.create(); //创建代理对象
        return obj;
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Order order = null;
        if (objects != null) {
            int oid = (int)objects[0];
            order = Cache.getInstance().getCache(oid);
            if (null == order){
                //调用真实的业务方法
                order = (Order)method.invoke(target, objects);
                Cache.getInstance().putCache(order.getOid(),order);
            }
        }
        return order;
    }
}

public class OrderDaoObject {
    public Order queryOrder(int oid) {
        //根据oid查询数据库,返回订单对象
        DB db = new DB();
        Order order = db.getOrder(oid);
        return order;
    }
}
public class TetstCglib {

    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        OrderDaoObject odo = new OrderDaoObject();
        OrderDaoObject odoProxy = (OrderDaoObject) cglibProxy.create(odo);
        Order order = odoProxy.queryOrder(4);
        System.out.println(order);
        System.out.println("-------第二次查询-------");
        Order order1 = odoProxy.queryOrder(4);
        System.out.println(order1);
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值