设计模式-代理(Proxy)模式

本文介绍了代理模式的基本概念,如静态代理和动态代理。静态代理通过手动创建代理类实现,而动态代理则分为基于接口的JDK动态代理和基于子类的CGLib动态代理。文章讨论了动态代理在性能上的差异,并指出Spring在创建Bean时会根据接口的存在与否选择使用JDK或CGLib。此外,还提到了MyBatis中的MapperProxy和数据源代理如AlibabaSeata的DataSourceProxy等应用。

基础/design-model

Spring-Aop_存在,及合理的博客-CSDN博客

给某一个对象提供一个代理,并由代理对象控制对原对象的引用

目标对象/被代理对象 ------ 房主:真正的租房的方法

代理对象 ------- 黑中介:有租房子的方法(调用房主的租房的方法)

执行代理对象方法的对象 ---- 租房的人

流程:我们要租房----->中介(租房的方法)------>房主(租房的方法)

抽象:调用对象----->代理对象------>目标对象

优点

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

缺点

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

 静态代理

 接口

  public interface HelloInterface {
    void sayHello();
}

被代理类

  public class Hello implements HelloInterface{
    @Override
    public void sayHello() {
        System.out.println("Hello zhanghao!");
    }}

代理类

  public class HelloProxy implements HelloInterface{
    private HelloInterface helloInterface = new Hello();
    @Override
    public void sayHello() {
        System.out.println("Before invoke sayHello" );
        helloInterface.sayHello();
        System.out.println("After invoke sayHello");
    }}

调用

   public static void main(String[] args) {
        HelloProxy helloProxy = new HelloProxy();
        helloProxy.sayHello();
    }
  输出:
Before invoke sayHello
Hello zhanghao!
After invoke sayHello

动态代理

  • 不用手动编写一个代理对象,不需要一一编写与目标对象相同的方法,这个过程,在运行时 的内存中动态生成代理对象
  • 字节码随用随创建,随用随加载
  • 对方法做一些增强

基于接口的动态代理 

提供者:JDK 官方的 Proxy 类。

要求:被代理类最少实现一个接口。

public interface IOrderDao {
    int insert(Order order);
}
public class OrderDaoImpl implements IOrderDao {
    @Override
    public int insert(Order order) {
        System.out.println("Dao层添加Order成功");
        return 1;
    }
}
public interface IOrderService {
    int saveOrder(Order order);
}
public class OrderServiceImpl implements IOrderService {
    private IOrderDao iOrderDao;
    @Override
    public int saveOrder(Order order) {
        iOrderDao = new OrderDaoImpl();
        System.out.println("Service层调用Dao层添加Order");
        return iOrderDao.insert(order);
    }
}

代理类 

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

    private void beforeMethod(Object obj){
        int userId = 0;
        System.out.println("动态代理 before code");
        if(obj instanceof Order){
            Order order = (Order)obj;
            userId = order.getUserId();
        }
        int dbRouter = userId % 2;
        System.out.println("动态代理分配到【db"+dbRouter+"】处理数据");

        //todo 设置dataSource;
        DataSourceContextHolder.setDBType("db"+String.valueOf(dbRouter));
    }

    private void afterMethod(){
        System.out.println("动态代理 after code");
    }
}
public class Test {
    public static void main(String[] args) {
        Order order = new Order();
        IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();
        orderServiceDynamicProxy.saveOrder(order);
    }
}

基于子类的动态代理

提供者:第三方的 CGLib

如果报 asmxxxx 异常,需要导入 asm.jar。要求:被代理类不能用 final 修饰的类(最终类)

主要是对指定的类生成一个子类,覆盖其中的方法,来实现代理对象。

public class CglibProxy {
    public static<T> T createProxy(T t){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(t.getClass());
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj,
                                    Method method, 
                                    Object[] args,
                                    MethodProxy proxy) throws Throwable {
               //可以在前后执行一些方法
                Object invoke = proxy.invokeSuper(obj,args);
                return invoke;
            }
        });

        Object o = enhancer.create();
        return (T) o;
    }
}

代理速度对比

  JDK动态代理 在万次之内比 CGLib 快

区别-装饰器、代理

  装饰器和代理之间的区别很细微,可以认为装饰器是代理的一个子集

  静态代理就是装饰器的方式

源码

spring

  当Bean有实现接口时,Spring就会用JDK的动态代理

  当Bean没有实现接口时, Spring使用CGlib

MyBatis

  UserMapper、CityMapper,mybatis帮我们写实现MapperProxy

Alibaba Seata的DataSourceProxy
DruidDataSource存在的Proxy模式
监控链...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值