结构化思维

步骤

对某一具体问题建立结构化思维主要分为两个大的步骤:
1、建立中心(问题)
2、对中心(问题)进行分解

第一步:建立中心

建立中心: 建立中心也就是要定义清楚要解决的问题,要明确目标,且不是一次就能建立成型的,需要多次

方式:
  1. 自上而下,适用于问题明确
  2. 自下而上,适用于不够明确复杂的问题,需要分类、剪枝、归纳汇总成中心

第二步:结构分解

主要分解方法

1) 演绎(因果)顺序:“大前提、小前提、结论”的演绎推理方式就是演绎顺序。
比如,经典三段论:所有人都要死,苏格拉底是人,苏格拉底要死。

2) 时间(步骤)顺序:“第一、第二、第三”,“首先、然后、再者”等,很多的时
间顺序同时也是因果顺序。

3) 空间(结构)顺序:“前端、后端、数据”,“波士顿、纽约、华盛顿”,化整为
零(将整体分解为部分)等都是空间顺序。

4) 程度(重要性)顺序: 比如“最重要、次重要、不重要”等。

注意: 满足 MECE(Mutually Exclusive Collectively Exhaustive,相互独立,完全穷尽)原则

其他工具:5W2H

参考资料

  • 阿里程序员的自我修养

JDK动态代理源码分析

环境支持

JDK代理是不需要第三方库支持的,只需要 JDK 环境就可以进行代理

使用条件:

  • 必须实现 InvocationHandler 接口;
  • 使用 Proxy.newProxyInstance 产生代理对象;
  • 被代理的对象必须要实现接口;

使用 JDK 动态代理 5 大步骤

  • 通过实现 InvocationHandler 接口来自定义自己的 InvocationHandler;
  • 通过 Proxy.getProxyClass 获得动态代理类;
  • 通过反射机制获得代理类的构造方法,方法签名为 getConstructor(InvocationHandler.class);
  • 通过构造函数获得代理对象并将自定义的 InvocationHandler 实例对象传为参数传入;
  • 通过代理对象调用目标方法;

案例

IHello 接口

public interface IHello {
    void sayHello();
}

IHello 接口实现类

public class HelloImpl implements IHello {

    @Override
    public void sayHello() {
        System.out.println("hello world !!! ");
    }
}

通过实现 InvocationHandler 接口来自定义 InvocationHandler;

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

public class MyInvocationHandler implements InvocationHandler {

    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在覆写的 invoke 方法内反射调用被代理对象的前后实现代码增强逻辑
        System.out.println("----- before invoke ------");
        Object result = method.invoke(target, args);
        System.out.println("----- after invoke ------");
        return result;
    }
}

测试

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;

public class MyProxyTest {

    public static void main(String[] args) {
        // 第一种方法
        demoOne();
        // 第二种方法
        demoTwo();
    }

    private static void demoTwo() {
        // 1、生成$Proxy0的class文件
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        // 2、Proxy.getProxyClass 获取动态代理类
        Class proxyClass = Proxy.getProxyClass(IHello.class.getClassLoader(), IHello.class);
        try {
            // 3、通过反射机制获得代理类的构造方法
            Constructor constructor = proxyClass.getConstructor(InvocationHandler.class);
            // 4、通过代理类构造函数来创建动态代理对象,将自定义的InvocationHandler实例传入
            IHello hello = (IHello) constructor.newInstance(new MyInvocationHandler(new HelloImpl()));
            // 5、通过代理对象调用目标方法
            hello.sayHello();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private static void demoOne() {
        IHello target = new HelloImpl();
        // 将2~4步骤封装好的简便方法来创建动态代理对象 $Proxy0
        // 注意:只能强转为接口类,不能是具体的实现类型
        IHello hello = (IHello) Proxy.newProxyInstance(IHello.class.getClassLoader(), 
            new Class[]{IHello.class}, 
            new MyInvocationHandler(target));
        hello.sayHello();
    }
}

源码分析

Proxy.newProxyInstance

    public static Object newProxyInstance(ClassLoader loader,  Class<?>[] interfaces,  InvocationHandler h)
        throws IllegalArgumentException {
        // 检查是否为null
        Objects.requireNonNull(h);
        // 拷贝所有接口类
        final Class<?>[] intfs = interfaces.clone();
        // 获取系统安全管理器
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
           // Reflection.getCallerClass返回调用该方法的方法的调用类;loader:接口的类加载器
           // 进行包访问权限、类加载器权限等检查
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         * 查找所有接口类的代理类
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            // 获取代理构造对象
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            // 检查代理构造对象构造方法权限,如果过不是public,设置为可访问
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            // 通过代理构造对象,创建代理类
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

newProxyInstance()方法主要执行逻辑

  • 生成代理类
    getProxyClass0(loader, intfs);
  • 获取构造器
    final Constructor<?> cons = cl.getConstructor(constructorParams);
  • 生成代理对象
    cons.newInstance(new Object[]{h});

获取代理对象类

private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }

    // If the proxy class defined by the given loader implementing
    // the given interfaces exists, this will simply return the cached copy;
    // otherwise, it will create the proxy class via the ProxyClassFactory
    // 提升性能,如果加载过从缓存中获取,没有通过 ProxyClassFactory 创建被代理类
    return proxyClassCache.get(loader, interfaces);
}

会在项目的根目录下的/com/sun/proxy/下生成名为$Proxy0.class 文件

package com.sun.proxy;

import com.gerry.pang.lettucedemo.service.IHello;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements IHello {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    //  重点:代理类中代理方法
    public final void sayHello() throws  {
        try {
            // InvocationHandler h;
            // 当前代理类对象,被类中方法, 方法入参
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            // 获取到被代理类中的hello方法对象
            m3 = Class.forName("com.gerry.pang.lettucedemo.service.IHello").getMethod("sayHello");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

总结

动态代理执行流程

JDK动态代理基于拦截器和反射来实现。通过Proxy.newProxyInstance 自动生成基于接口的被代理对象的类 $Proxy0,在这个类继承了Proxy类,同时实现了IHello接口,即代理类接口,覆写了sayHello方法,其内部是通过反射调用被代理类的sayHello方法,也就是说这里就是个壳子。