Jdk动态代理个人简单梳理

java动态代理在Spring的AOP中可谓是被应用到了极致,一直不是很清楚,今天想复习一下设计模式,刚好看到动态代理一下就把我的思绪拉回到看AOP源码的时光了,说实话动态代理我用的太少了,于是今天小总结一下,来看看。

引入如下场景:房东想租房子,但是他只想租不想管其余的琐事,于是他找中介,把房子托给他,这个中介就是一个代理者。

静态代理,十分简单:就是代理者内部聚合一个接口,这个接口是房东和中介共有的,这样就实现了静态的代理,这里就不再赘述了,代码贴出来看一眼就懂了。

// 被代理类和代理类共同的操作
interface Action {
    default void doOther() {
    };

    void display();
}
// 被代理类【房东】
class Host implements Action {

    @Override
    public void display() {
        System.out.println("我是房东,我只想租房子,啥也不想管");
    }
}
// 代理类【中介】
class HostProxy implements Action {
    private Action action;

    public HostProxy() {
        action = new Action() {
            @Override
            public void display() {
                System.out.println("do nothing...");
            }
        };
    }

    public HostProxy(Action action) {
        this.action = action;
    }

    @Override
    public void display() {
        PostProcessorsBeforeAction();
        action.display();
        PostProcessorsAfterAction();
    }

    private void PostProcessorsBeforeAction() {
        System.out.println("我来代理你做吧");
    }

    private void PostProcessorsAfterAction() {
        System.out.println("代理执行后序到结束");
    }
}

动态代理:

// 动态代理雏形...
Action host = new Host();
InvocationHandler invocationHandler = new InvocationHandler() {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("动态代理之前干事情");
        host.display();
        System.out.println("动态代理完成");
        return null;
    }
};
Action actionProxy = (Action) Proxy.newProxyInstance(Action.class.getClassLoader(), new Class[]{Action.class}, invocationHandler);
actionProxy.display();

个人写动态代理【简单版,有时间继续探讨】:

// 自己写一下动态代理
class DynamicProxy<T> {
    public T getProxy(Class<?> clazz, T obj, Object... args){
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("动态代理之前干的...事情");
                // 原方法调用(这里只测试有一个方法,我取出第一个就好)
                // Method[] methods = obj.getClass().getMethods();
                // methods.invoke(obj, args);
                method.invoke(obj, args);
                System.out.println("动态代理完成啦...");
                return null;
            }
        };
        T proxyInstance = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, invocationHandler);
        return proxyInstance;
    }
}
// 动态代理
DynamicProxy<Action> dynamicProxy = new DynamicProxy();
Action proxy = dynamicProxy.getProxy(Action.class, new Host());
proxy.display();

动态代理稍微深入一些:

先不和Spring的Aop写的那么复杂,我先简单实现一下,其中NxjBefore就是前置方法,NxjAfter就是后置方法
// 定义这两个注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface NxjBefore {
}

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface NxjAfter {
}
// 接口
interface IMyReflect {
    void display();
}
// 被代理类
class MyReflect implements IMyReflect{
    @Override
    public void display() {
        System.out.println("执行方法");
    }
}
class MyReflectTest{
    /**
     * 为了测试,包含注解有NxjBefore;NxjAfter这两个先测试
     */
    @NxjBefore
    public void test01() {
        System.out.println("嗯哼,before啦");
    }

    @NxjAfter
    public void test02() {
        System.out.println("嗯哼,after啦");
    }
}
// 自己写一下动态代理(大框和上方写的一样)
static class DynamicProxy<T> {
    public T getProxy(Class<?> clazz, T obj, Object aop, Object... args){
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("动态代理之前干的...事情");
                // 排好顺序
                Map<Class<?>, List<Method>> chain = chain(aop.getClass().getMethods());
                // 顺序调用(可以仿照Spring中AOP递归调用,这里我先简单测试一下)
                List<Method> listBefore = chain.get(NxjBefore.class);
                for (Method method1 : listBefore) {
                    method1.invoke(aop);
                }
                method.invoke(obj,args);
                List<Method> listAfter = chain.get(NxjAfter.class);
                for (Method method1 : listAfter) {
                    method1.invoke(aop);
                }
                System.out.println("动态代理完成啦...");
                return null;
            }
        };
        T proxyInstance = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, invocationHandler);
        return proxyInstance;
    }
}
private static Map<Class<?>, List<Method>> chain(Method[] methods) {
    Map<Class<?>, List<Method>> res = new HashMap<>();
    List<Method> beforeList = new ArrayList<>();
    List<Method> afterList = new ArrayList<>();
    for (Method method : methods) {
        Annotation[] annotations = method.getDeclaredAnnotations();
        for (Annotation annotation : annotations) {
            Class<? extends Annotation> aClass = annotation.annotationType();
            if (aClass.equals(NxjBefore.class)) {
                beforeList.add(method);
                break;
            } else if (aClass.equals(NxjAfter.class)) {
                afterList.add(method);
            }
        }
    }
    res.put(NxjBefore.class, beforeList);
    res.put(NxjAfter.class, afterList);
    return res;
}
public static void main(String[] args) {
    DynamicProxy<IMyReflect> dynamicProxy = new DynamicProxy();
    IMyReflect proxy = dynamicProxy.getProxy(IMyReflect.class, new MyReflect(), new MyReflectTest());
    proxy.display();
}
# 结果
动态代理之前干的...事情
嗯哼,before啦
执行方法
嗯哼,after啦
动态代理完成啦...

当然Spring中Aop中应用动态代理,方法执行是递归执行,大致过程为先通过方法获取链chain[此时代理对象内部方法就是按照注解标注的方式排序好的],然后递归执行方法,由后往前,当是最后一个方法是调用invoke,然后依次弹栈执行。

一篇很好的文章,值的看看:https://www.cnblogs.com/gonjan-blog/p/6685611.html

posted @ 2021-02-01 13:06  程序杰杰  阅读(72)  评论(0编辑  收藏  举报