• MyBatis - 代理


    在不改变原有代码情况下,实现对原有代码的增强

    案例

    张三找律师打官司

    静态代理

    特点:代理类代码是写死的

    优点:在不改变原有代码的情况下实现了对原有业务增强

    缺点:一个目标类就需要一个代理类,不便于业务拓展

    1. 定义接口,规定核心业务(代理对象与目标对象做的是一样的事情)

      1. //规定代理对象与目标对象之间所做的核心业务
      2. public interface Speak {
      3. void say();
      4. }
    2. 编写目标类(实现核心的业务)

      1. public class 张三类 implements Speak{
      2. @Override
      3. public void say() {
      4. System.out.println("我每天吃一顿饭,挨三顿打。我请求离婚");
      5. }
      6. }
    3. 编写代理类(代理目标类--实现对目标的增强)

      1. public class 律师类 implements Speak {
      2.    // 创建目标类
      3.    private 张三类 张三;    
      4.    public 律师类(张三类 张三) {
      5.        this.张三 = 张三;
      6.   }
      7.    @Override
      8.    public void say() {
      9.        System.out.println("巴拉巴拉...接下来由原告述说");
      10.        张三.say();// 真正做核心业务还是目标对象,代理对象只是在目的对象的基础上增强
      11.   }
      12. }
    4. 测试

      1. public static void main(String[] args) {
      2.    张三类 张三 = new 张三类();
      3.    律师类 律师 = new 律师类(张三);
      4.    // 真正的是代理类方法
      5.    律师.say();
      6. }

    动态代理

    特点:代理类代码是动态生成

    JDK动态代理

    特点

    1. 基于接口实现(invocationhandler)

    2. 根据不同目标对象,生成不同代理对象

    实现

    1. 定义接口,规定核心业务

      1. public interface Speak {
      2. void say();
      3. }
    2. 编写目标类

      1. public class 张三类 implements Speak{
      2. @Override
      3. public void say() {
      4. System.out.println("我每天吃一顿饭,挨三顿打。我请求离婚");
      5. }
      6. }
    3. 编写JDK动态代理

      1. public class JDKProxy implements InvocationHandler {
      2.    // 目标对象
      3.    private Object 客户;
      4.    public JDKProxy(Object obj) {
      5.        this.客户 = obj;
      6.   }
      7.    // 增强代码写在invoke方法
      8.    // proxy:代理对象
      9.    // method:待增强的方法(接口中定义的方法)
      10.    // args:待增强方法的参数
      11.    @Override
      12.    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      13.        System.out.println("巴拉巴拉...接下来由原告述说");
      14.        // 用完目标对象方法时可能有返回
      15.        Object result = method.invoke(客户, args);
      16.        return result;
      17.   }
      18. }
    4. 生成代理对象

      1. public static void main(String[] args) {
      2.    张三类 张三 = new 张三类();
      3.    // 调用Proxy类的newProxyInstance静态方法生成代理对象
      4.    Speak speak = (Speak) Proxy.newProxyInstance(张三.getClass().getClassLoader(), 张三.getClass().getInterfaces(), new JDKProxy(张三));
      5.    speak.say();
      6. }

    CGLIB动态代理

    特点

    基于类的继承实现(MethodInterceptor)

    需要导包(cglib、asm)

    实现

    1. 编写目标对象

      1. public class 张三类{
      2. public void say() {
      3. System.out.println("我每天吃一顿饭,挨三顿打。我请求离婚");
      4. }
      5. }
    2. 编写代理类(实现MethodInterceptor)

      1. public class MyProxy implements MethodInterceptor {
      2.    // 目标对象
      3.    private Object target;
      4.    public MyProxy(Object obj) {
      5.        this.target = obj;
      6.   }
      7.    // intercept:编写增强的代码
      8.    // method:待增强的方法
      9.    // arg:待增强的方法需要的参数
      10.    @Override
      11.    public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy arg3) throws Throwable {
      12.        System.out.println("巴拉巴拉...接下来由原告述说");
      13.        Object result = method.invoke(target, arg2);//目标对象方法的返回值 如果为void 则为null
      14.        return result;
      15.   }
      16. }
    3. 获取代理对象

      1. public static void main(String[] args) {
      2.    张三类 张三 = new 张三类();
      3.    MyProxy myProxy = new MyProxy(张三);
      4.    // 第一个参数:目标对象类型
      5.    // 第二个参数:实现MethodInterceptor类的对象
      6.    张三类 create = (张三类) Enhancer.create(张三.getClass(), myProxy);
      7.    create.say();
      8. }

    注意

    代理类中默认将接口所有方法进行增强,若想对指定方法增强可自定义注解打标记,代理类中去判断标记

    创建注解

    1. @Target(ElementType.METHOD)
    2. @Retention(RetentionPolicy.RUNTIME)
    3. public @interface NeedAdd {}

    方法中添加注解

    1. public interface Speak {
    2. @NeedAdd
    3. void say();
    4. int cry(int time);
    5. }

    根据方法是否存在注解进行使用

    1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    2.    Object result = null;
    3.    // 判断是否存在注解标记
    4.    if(method.isAnnotationPresent(NeedAdd.class)) {
    5.        System.out.println("巴拉巴拉...接下来由原告述说");
    6.        // 用完目标对象方法时可能有返回
    7. result = method.invoke(客户, args);
    8.   }else {
    9.        // 用完目标对象方法时可能有返回
    10.        result = method.invoke(target, args);
    11.   }
    12.    return result;
    13. }
  • 相关阅读:
    PCB布线及后仿真验证过程(干货满满,建议收藏)
    国微FPGA培训
    Java项目:SSM智能制造车间管理系统
    可替代角雷达,这款纯固态补盲激光雷达什么来头?
    入门力扣自学笔记120 C++ (题目编号1417)
    自身免疫疾病诊断原料厂家——博迈伦
    OpenCV之cv::undistort
    XXL-Job和Elastic-job的区别
    澳大利亚博士后招聘|国立大学—太阳能电池方向
    大数据组件Sqoop-安装与验证
  • 原文地址:https://blog.csdn.net/Xstruggle/article/details/125487948