Spring之代理模式

为什么要用代理模式?
  • 中介隔离作用:
    在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。

  • 开闭原则,增加功能:
    代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类.

代理模式:

        代理模式作为23种经典设计模式之一,其比较官方的定义为“为其他对象提供一种代理以控制对这个对象的访问”,简单点说就是,之前A类自己做一件事,在使用代理之后,A类不直接去做,而是由A类的代理类B来去做

1.静态代理

        特点是代理对象是针对指定的目标做的, 所有代码都固定的, 由程序员提供. 代码实现非常简单, 不能复用.

静态代理代码如下:

/**
 * 标准 - 房屋租赁接口
 */
public interface Rent {
    /**
     * 出租房屋的方法
     *
     * @param money
     * @return
     */
    Object rent(Object money);
}
/**
 * 真实对象 - 房东
 */
public class Host implements Rent {
    @Override
    public Object rent(Object money) {
        System.out.println("出租成功, 价格是: " + money);
        return new Object();
    }
}
/**
 * 代理对象 - 中介人员
 */
public class Agent implements Rent {
    private Rent host;

    public Rent getHost() {
        return host;
    }

    public void setHost(Rent host) {
        this.host = host;
    }

    @Override
    public Object rent(Object money) {
        // 前置增强
        System.out.println("带客户看房");
        System.out.println("讲价");
        System.out.println("签订合同");
        // 调用业主的方法进行房屋的出租
        Object key = host.rent(money);
        // 后置增强
        System.out.println("客户信息登记...");
        System.out.println("客户维护...");
        return key;
    }
}
/**
 * 客户 - 租客
 */
public class Customer {
    public static void main(String[] args) {
        // 找中介
        Agent proxy = new Agent();
        // 中介找业主
        proxy.setHost(new Host());
        // 租房
        Object key = proxy.rent(2000);
    }
}

2.动态代理

        特点是代理对象不是固定的, 代码是由后台根据情况生成的. 代理功能更加通用. 代码实现复杂, 可以复用.

动态代理的实现方式有两种:
2.1 jdk动态代理

jdk中自带的动态代理实现方案. Proxy类和InvocationHandler接口.

  • 生成的代理对象都是Proxy类的子类.
  • 动态代理中额外增强的功能, 被称之为调用处理程序. 必须实现InvocationHandler接口.
  • 必须提供接口.
  • 生成的代理类和真实类是实现了相同接口的. 它俩不能互相转换, 否则会抛出ClassCastException.

    代码如下:
/**
 * 标准 - 接口
 */
public interface Rent {
    /**
     * 租房方法
     *
     * @param money
     * @return
     */
    Object rent(Object money);
}
/**
 * 真实对象 - 业主
 */
public class Host implements Rent {
    @Override
    public Object rent(Object money) {
        System.out.println("出租成功, 价格: " + money);
        return new Object();
    }
}
/**
 * 中介公司 - 调用处理程序
 */
public class Agent implements InvocationHandler {
    private Rent host;

    public Rent getHost() {
        return host;
    }

    public void setHost(Rent host) {
        this.host = host;
    }

    /**
     * 将来被自动调用
     *  1. 最终需要调用业主的方法把房子租出去
     *  2. 对这个功能要进行增强
     * @param proxy 代理对象
     * @param method 正在被调用的方法
     * @param args 被调用方法的参数列表
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置增强
        System.out.println("签合同...");
        // 调用真实对象的方法
        Object result = method.invoke(host, args);
        // 后置增强
        System.out.println("客户登记...");
        return result;
    }

    /**
     * 获取代理对象
     *
     * @return
     */
    public Rent getProxy() {
        return (Rent) Proxy.newProxyInstance(
                Agent.class.getClassLoader(),
                new Class<?>[]{Rent.class},
                this);
    }
}
public class Customer {
    public static void main(String[] args) {
        // 中介公司
        Agent agent = new Agent();
        // 中介公司找业主
        agent.setHost(new Host());
        // 从中介公司获取代理对象
        Rent proxy = agent.getProxy();
        System.out.println(proxy.getClass().getName());
        System.out.println(proxy.getClass().getSuperclass().getName());
        // 调用代理对象的租房方法
        proxy.rent(3000);
    }
}
2.2 cglib动态代理
  • 需要额外导包, cglib相关的jar包: cglib.jar, asm.jar
  • 不需要提供接口, 代理类是真实类的子类.
  • 调用处理程序需要实现MethodInterceptor接口.
/**
 * 真实对象 - 业主
 */
public class Host {
    public Object rent(Object money) {
        System.out.println("房屋出租, 价格: " + money);
        return new Object();
    }
}
/**
 * 中介公司 - 调用处理程序
 */
public class Agent implements MethodInterceptor {
    /**
     * 方法拦截
     *  1. 调用真实类中的方法
     *  2. 需要对真实类中的方法进行增强
     *
     * @param obj 代理对象
     * @param method 被调用的方法
     * @param args 方法的参数列表
     * @param methodProxy 被代理的方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 前置增强
        System.out.println("[前置]");
        // 调用真实类中的方法
        Object result = methodProxy.invokeSuper(obj, args);
        // 后置增强
        System.out.println("[后置]");
        return result;
    }

    public Host getProxy() {
        // 创建增强子Enhancer
        Enhancer enhancer = new Enhancer();
        // 设置父类型
        enhancer.setSuperclass(Host.class);
        // 设置回调
        enhancer.setCallback(this);
        // 创建代理对象
        return (Host) enhancer.create();
    }
}
public class Customer {
    public static void main(String[] args) {
        // 找中介
        Agent agent = new Agent();
        // 获取代理对象
        Host proxy = agent.getProxy();
        System.out.println(proxy.getClass().getName());
        System.out.println(proxy.getClass().getSuperclass().getName());
        // 调用方法进行租房
        proxy.rent(500);
    }
}
发布了320 篇原创文章 · 获赞 152 · 访问量 64万+

猜你喜欢

转载自blog.csdn.net/hello_word2/article/details/104827411