Jdk 动态代理

文章目录

  • 一、简介


一、简介

在Java中,包含两种动态代理:

  • 基于Jdk的动态代理
  • 基于Cglib的动态代理

两种动态代理的主要区别:

  • Jdk动态代理生成的代理对象会默认继承Proxy类,Java是单继承多实现,因此它是基于接口的动态,也就是说代理类至少需要实现一个接口。
  • Cglib的动态代理是基于类的动态代理。

在学习Springframework 的 AOP模块时,其核心就是动态代理,如果Bean实现了某个接口,那么默认使用的基于Jdk的动态代理,如果Bean没有实现任何接口,那么使用的是Cglib的动态代理。

Jdk动态代理有两个核心类,分别是InvocationHandler(这是个函数式接口)、Proxy(类),这两个类都在java.lang.reflect包下面。这里我就不去讲JDK动态代理的原理了,网上有很多相关博客教程,我这里写了几个工具类供大家使用,直接上代码吧。

定义接口


/**
 * Target Object
 *
 * @author : sungm
 * @date : 2020-12-03 15:48
 */
public interface Target {
     

    /**
     * doSomething
     */
    void doSomething();

}

定义接口的默认实现类

package com.miracle.proxy.jdk;

/**
 * @author : sungm
 * @date : 2020-12-03 15:49
 */
public class DefaultTarget implements Target {
     

    /**
     * doSomething
     */
    @Override
    public void doSomething() {
     
        System.out.println("基于Java的动态代理");
    }

}

工具类一:提供自定义抽象的InvocationHandler类

package com.miracle.reflect.jdk.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 基于JDK的动态代理
 *
 * @author : sungm
 * @date : 2020-12-03 15:38
 */
public abstract class BaseInvocationHandler<T> implements InvocationHandler {
     

    /**
     * 目标对象。条件:目标类至少实现一个接口
     */
    private T t;

    /**
     * 获取代理对象
     *
     * @param t target object
     * @return proxy object
     */
    public Object getProxy(T t) {
     
        this.t = t;
        return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     
        before(proxy, t, method, args);
        @SuppressWarnings("unchecked")
        //这里不能调用代理对象proxy, 因为proxy会再次调用该方法,然后就进入死循环了,所以这里必须使用目标对象t
        final T invoke = (T) method.invoke(t, args);
        after(proxy, t, method, args);
        return invoke;
    }

    /**
     * method invoke before call before method;
     * @param proxy     proxyObject
     * @param target    targetObject
     * @param method    method
     * @param args      args
     */
    protected abstract void before(Object proxy, T target, Method method, Object[] args);

    /**
     * method invoke after call after method;
     * @param proxy     proxyObject
     * @param target    targetObject
     * @param method    method
     * @param args      args
     */
    protected abstract void after(Object proxy, T target, Method method, Object[] args);

    /**
     * 测试
     *
     * @param args a
     */
    public static void main(String[] args) {
     
        BaseInvocationHandler<Target> invocationHandler = new BaseInvocationHandler<Target>() {
     
            @Override
            protected void before(Object proxy, Target target, Method method, Object[] args) {
     
                System.out.println("指定" + method.getName() + "方法执行之前执行当前before方法");
            }

            @Override
            protected void after(Object proxy, Target target, Method method, Object[] args) {
     
                System.out.println("指定" + method.getName() + "方法执行之后执行当前after方法");
            }
        };
        Target target = (Target) invocationHandler.getProxy(new DefaultTarget());
        target.doSomething();
    }

工具类二:提供JdkProxyUtils

package com.miracle.reflect.jdk.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @author : sungm
 * @date : 2021-04-09 10:53
 */
public class JdkProxyUtils {
     

    private JdkProxyUtils() {
     }

    /**
     * 推荐使用:代理对象,增强方法一步到位
     *
     * @param t target object
     * @param before before consumer
     * @param after after consumer
     * @return proxy object
     */
    public static <T> Object getProxy(T t, BiConsumer<Method, Object[]> before, BiConsumer<Method, Object[]> after) {
     
        return getProxy(t, getInvocationHandler(t, before, after));
    }

    /**
     *
     * @param t target object
     * @param ih InvocationHandler instance
     * @return proxy object
     */
    public static <T> Object getProxy(T t, InvocationHandler ih) {
     
        return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), ih);
    }

    /**
     * 获取InvocationHandler
     *
     * @param t target object
     * @param before before consumer
     * @param after  after consumer
     * @return InvocationHandler instance
     */
    public static <T> InvocationHandler getInvocationHandler(T t, BiConsumer<Method, Object[]> before
            , BiConsumer<Method, Object[]> after) {
     
        return (Object proxy, Method method, Object[] args) -> {
     
            //执行before方法
            if (Objects.nonNull(before)) {
     
                before.accept(method, args);
            }

            //执行目标方法
            final Object result = method.invoke(t, args);

            //执行after方法
            if (Objects.nonNull(after)) {
     
                after.accept(method, args);
            }

            //返回目标方法执行结果
            return result;
        };
    }

    public static void main(String[] args) {
     
        Consumer<Object[]> consumer = params -> Optional.ofNullable(params).ifPresent(array -> {
     
            final String values = Arrays.stream(array)
                    .filter(Objects::nonNull)
                    .map(Object::toString)
                    .collect(Collectors.joining("、"));
            System.out.println("方法的参数列表为:" + values);
        });
        BiConsumer<Method, Object[]> before = (method, params) -> {
     
            System.out.println(method.getName() + "方法执行之前被执行before方法");
            consumer.accept(params);
        };
        BiConsumer<Method, Object[]> after = (method, params) -> {
     
            System.out.println(method.getName() + "方法执行之后被执行after方法");
            consumer.accept(params);
        };

        Target target = new DefaultTarget();
        final Target proxy = (Target) JdkProxyUtils.getProxy(target, before, after);
        proxy.doSomething();
    }

}

最后,请大家点个赞吧…

你可能感兴趣的:(java,proxy)