系列三十三、代理(三)动态代理

一、概述

        在实际开发过程中,往往我们自己不会去创建代理类,而是通过JDK提供的Proxy类在程序运行时,运用反射机制动态创建而成,这就是所谓的动态代理。 

1.1、动态代理 vs 静态代理

        静态代理需要程序员自己写代理类,动态代理不需要。动态代理虽然不需要程序员自己写代理类了,但是还是需要我们定义对被代理对象直接访问方法的拦截,用于对拦截的方法做增强。动态代理技术在框架中使用的场景很多,例如:MyBatis、Spring、SpringMVC等

二、API

2.1、Proxy

public class Proxy extends Object implements Serializable

提供了用于创建动态代理类和对象的静态方法

系列三十三、代理(三)动态代理_第1张图片

2.2、InvocationHandler

三、案例代码

3.1、pom


  
    junit
    junit
    4.13.2
  
  
  
    org.projectlombok
    lombok
    1.18.22
  
  
    org.slf4j
    slf4j-api
    1.7.32
  
  
    ch.qos.logback
    logback-classic
    1.2.10
  

3.2、Star

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2023/10/29 23:31
 * @Description: 抽象角色
 */
public interface Star {
    /**
     * 唱歌
     * @param musicName 歌曲名字
     * @return
     */
    String sing(String musicName);
    /**
     * 跳舞
     */
    void dance();
}

3.3、SuperStar

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2023/10/29 23:32
 * @Description: 被代理角色
 */
@Data
public class SuperStar implements Star {

    /**
     * 歌手名字
     */
    private String starName;

    public SuperStar() {
    }

    public SuperStar(String starName) {
        this.starName = starName;
    }

    @Override
    public String sing(String musicName) {
        System.out.println(this.starName + "正在唱:" + musicName);
        return "谢谢!谢谢!";
    }

    @Override
    public void dance() {
        System.out.println(this.starName + "正在优美的跳舞");
    }
}

3.4、MyInvocationHandler

@Slf4j
public class MyInvocationHandler implements InvocationHandler {

    private Object obj;

    public MyInvocationHandler(Object obj) {
        this.obj = obj;
    }

    /**
     * 增强逻辑
     *
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 目标方法执行之前
        log.info("目标方法执行之前执行,目标方法名称:{},入参:{}", method.getName(), Arrays.toString(args));
        // 目标方法执行
        Object result = method.invoke(obj, args);
        // 目标方法执行之后
        log.info("目标方法执行之后执行,result:{},obj:{}",result,obj.getClass());
        return result;
    }
}

3.5、测试

@Slf4j
public class App {
    public static void main(String[] args) {
        m4();
    }

    /**
     * Star动态代理:实现InvocationHandler接口方式
     */
    private static void m4() {
        Star targetObj = new SuperStar("杨超越");
        MyInvocationHandler proxy = new MyInvocationHandler(targetObj);
        Star proxyObj = (Star) Proxy.newProxyInstance(targetObj.getClass().getClassLoader(), targetObj.getClass().getInterfaces(), proxy);

        String result = proxyObj.sing("奢香夫人");

        System.out.println("result = " + result);

        proxyObj.dance();
    }

    /**
     * Star动态代理:匿名内部类方式
     */
    private static void m3() {
        // target
        SuperStar target = new SuperStar("杨超越");

        // 被代理对象的类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();

        // 被代理对象实现的所有接口
        Class[] interfaces = target.getClass().getInterfaces();

        Star proxyStar = (Star) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
            /**
             * invoke方法的执行实际:
             *      代理对象调用方法,就会触发此方法执行
             *
             * invoke方法的参数:
             *      参数1:Object proxy,代理对象,不用!
             *      参数2:Method method,代理对象调用的方法,封装Method对象
             *      参数3:Object[] args,数组里存放的是代理对象调用目标方法传递的数据
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                log.info("方法名称:{},参数:{}", method.getName(), Arrays.asList(args));
                log.info("target Method execute before");

                Object result = method.invoke(target, args);

                log.info("目标方法返回结果:{}",result);

                System.out.println("target Method execute after");

                return result;
            }
        });
        System.out.println("proxyStar = " + proxyStar.getClass());

        String result = proxyStar.sing("奢香夫人");
        System.out.println("result = " + result);
    }

}

系列三十三、代理(三)动态代理_第2张图片

你可能感兴趣的:(Spring全家桶面试系列,java,开发语言)