美文网首页
Spring源码解析(十三)-DisposableBeanAda

Spring源码解析(十三)-DisposableBeanAda

作者: 秋水畏寒 | 来源:发表于2020-05-11 23:33 被阅读0次

Spring版本

5.2.5.RELEASE

源码解析

1. DisposableBeanAdapter

    public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,
            List<BeanPostProcessor> postProcessors, @Nullable AccessControlContext acc) {

        Assert.notNull(bean, "Disposable bean must not be null");
        this.bean = bean;
        this.beanName = beanName;
        this.invokeDisposableBean =
                (this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy"));
        this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
        this.acc = acc;
        // 对destroyMethodName进行推断
        String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);
        // 1、推断结果不为空
        // 2、invokeDisposableBean为false,或者destroyMethodName = destroy
        // 3、destroyMethodName不由beanDefinition进行外部管理(看方法名是这个意思,不代表正确说法)
        if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&
                !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
            this.destroyMethodName = destroyMethodName;
            // 通过destroyMethodName获取到对应的method
            Method destroyMethod = determineDestroyMethod(destroyMethodName);
            if (destroyMethod == null) {
                // 如果destroyMethod为空,但是beanDefinition有强制要求执行销毁方法,此时抛出异常
                if (beanDefinition.isEnforceDestroyMethod()) {
                    throw new BeanDefinitionValidationException("Could not find a destroy method named '" +
                            destroyMethodName + "' on bean with name '" + beanName + "'");
                }
            }
            else {
                Class<?>[] paramTypes = destroyMethod.getParameterTypes();
                if (paramTypes.length > 1) {
                    // 销毁方法参数个数不能多于1个
                    throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
                            beanName + "' has more than one parameter - not supported as destroy method");
                }
                else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
                    // 销毁方法的唯一参数只能是boolean类型
                    throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
                            beanName + "' has a non-boolean parameter - not supported as destroy method");
                }
                // 获取接口方法
                destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod);
            }
            this.destroyMethod = destroyMethod;
        }
        // 从postProcessors查找到所有适用于bean的销毁processors
        this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
    }

构造方法中,除了一些简单的赋值之类,还有几个处理方法:
首先通过inferDestroyMethodIfNecessary推算出销毁方法名称,如果方法名称同时满足以下三个条件:

  • 不为空
  • invokeDisposableBeanfalse,或者destroyMethodName = destroy
  • destroyMethodName不由beanDefinition进行外部管理(看方法名是这个意思,不代表正确说法)
    那么,通过destroyMethodName去获取销毁方法destroyMethod,之后通过destroyMethod获取接口层面上destroyMethod,最后从postProcessors查找到所有适用于bean的销毁processors

2. inferDestroyMethodIfNecessary

    @Nullable
    private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
        String destroyMethodName = beanDefinition.getDestroyMethodName();
        // 如果destroyMethodName是INFER_METHOD,那么推断出真正的destroyMethodName
        if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
                (destroyMethodName == null && bean instanceof AutoCloseable)) {
            // Only perform destroy method inference or Closeable detection
            // in case of the bean not explicitly implementing DisposableBean
            if (!(bean instanceof DisposableBean)) {
                try {
                    // 获取close方法
                    return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
                }
                catch (NoSuchMethodException ex) {
                    try {
                        // 没有close方法,则获取shutdown方法
                        return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
                    }
                    catch (NoSuchMethodException ex2) {
                        // no candidate destroy method found
                    }
                }
            }
            return null;
        }
        return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
    }

3. determineDestroyMethod

    @Nullable
    private Method determineDestroyMethod(String name) {
        try {
            if (System.getSecurityManager() != null) {
                return AccessController.doPrivileged((PrivilegedAction<Method>) () -> findDestroyMethod(name));
            }
            else {
                // 查找对应于name的方法
                return findDestroyMethod(name);
            }
        }
        catch (IllegalArgumentException ex) {
            throw new BeanDefinitionValidationException("Could not find unique destroy method on bean with name '" +
                    this.beanName + ": " + ex.getMessage());
        }
    }

4. findDestroyMethod

    @Nullable
    private Method findDestroyMethod(String name) {
        // 如果允许访问非public方法,则从declareMethods中查找
        // 否则,只从methods中查找
        return (this.nonPublicAccessAllowed ?
                BeanUtils.findMethodWithMinimalParameters(this.bean.getClass(), name) :
                BeanUtils.findMethodWithMinimalParameters(this.bean.getClass().getMethods(), name));
    }

这里的逻辑比较简单,如果允许访问非public方法:

  1. 先从clazz.getMethods()查找
  2. 如果找不到,则从clazz.getDeclareMethods()中查找
  3. 如果还是查找不到,获取父类,重复步骤1

如果不允许访问非public方法,直接通过clazz.getMethods()中查找

getMethodsgetDeclareMethods的区别在于,getMethod仅获取所有public方法,包含继承的public方法,getDeclareMethods可以获取到类中声明的publicprivateprotecteddefault方法,但不包含继承的方法

5. findMethodWithMinimalParameters

    @Nullable
    public static Method findMethodWithMinimalParameters(Class<?> clazz, String methodName)
            throws IllegalArgumentException {

        // 找到符合methodName的method,且形参个数最少,最好是0
        Method targetMethod = findMethodWithMinimalParameters(clazz.getMethods(), methodName);
        if (targetMethod == null) {
            // 如果找不到,则从clazz的declareMethod中查找
            targetMethod = findDeclaredMethodWithMinimalParameters(clazz, methodName);
        }
        return targetMethod;
    }

6. findMethodWithMinimalParameters

    @Nullable
    public static Method findMethodWithMinimalParameters(Method[] methods, String methodName)
            throws IllegalArgumentException {

        Method targetMethod = null;
        int numMethodsFoundWithCurrentMinimumArgs = 0;
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                int numParams = method.getParameterCount();
                // 如果targetMethod为空(for循环第一次进来)
                // 或者method的形参个数比targetMethod的形参个数少
                // 意味着targetMethod是我们想找的方法
                if (targetMethod == null || numParams < targetMethod.getParameterCount()) {
                    targetMethod = method;
                    numMethodsFoundWithCurrentMinimumArgs = 1;
                }
                else if (!method.isBridge() && targetMethod.getParameterCount() == numParams) {
                    // 如果之前找到的targetMethod是桥接方法,且进入这一分支意味着method不是桥接方法
                    // 那么替换targetMethod
                    if (targetMethod.isBridge()) {
                        // Prefer regular method over bridge...
                        targetMethod = method;
                    }
                    else {
                        // Additional candidate with same length
                        // 找到多个候选值,计量器+1
                        numMethodsFoundWithCurrentMinimumArgs++;
                    }
                }
            }
        }
        // 候选值超过1个,抛出异常,只想要唯一一个
        if (numMethodsFoundWithCurrentMinimumArgs > 1) {
            throw new IllegalArgumentException("Cannot resolve method '" + methodName +
                    "' to a unique method. Attempted to resolve to overloaded method with " +
                    "the least number of parameters but there were " +
                    numMethodsFoundWithCurrentMinimumArgs + " candidates.");
        }
        return targetMethod;
    }

7. findDeclaredMethodWithMinimalParameters

    @Nullable
    public static Method findDeclaredMethodWithMinimalParameters(Class<?> clazz, String methodName)
            throws IllegalArgumentException {

        // 从declareMethod中查找符合methodName的method,且形参个数最少吗,最好是0
        Method targetMethod = findMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName);
        if (targetMethod == null && clazz.getSuperclass() != null) {
            // 如果找不到,从父类递归本方法查找
            targetMethod = findDeclaredMethodWithMinimalParameters(clazz.getSuperclass(), methodName);
        }
        return targetMethod;
    }

8. getInterfaceMethodIfPossible

    public static Method getInterfaceMethodIfPossible(Method method) {
        // 如果不是public方法
        // 或者method所属类本身就是一个interface
        if (!Modifier.isPublic(method.getModifiers()) || method.getDeclaringClass().isInterface()) {
            return method;
        }
        // 否则,从interfaceMethodCache获取,如果interfaceMethodCache不存在,则查找,并将结果写入interfaceMethodCache
        return interfaceMethodCache.computeIfAbsent(method, key -> {
            Class<?> current = key.getDeclaringClass();
            while (current != null && current != Object.class) {
                Class<?>[] ifcs = current.getInterfaces();
                for (Class<?> ifc : ifcs) {
                    try {
                        return ifc.getMethod(key.getName(), key.getParameterTypes());
                    }
                    catch (NoSuchMethodException ex) {
                        // ignore
                    }
                }
                // 获取父类,继续循环
                current = current.getSuperclass();
            }
            return key;
        });
    }

从method获取到接口层级的method,并进行缓存

9.filterPostProcessors

    @Nullable
    private List<DestructionAwareBeanPostProcessor> filterPostProcessors(List<BeanPostProcessor> processors, Object bean) {
        List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
        if (!CollectionUtils.isEmpty(processors)) {
            filteredPostProcessors = new ArrayList<>(processors.size());
            for (BeanPostProcessor processor : processors) {
                if (processor instanceof DestructionAwareBeanPostProcessor) {
                    DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor;
                    if (dabpp.requiresDestruction(bean)) {
                        filteredPostProcessors.add(dabpp);
                    }
                }
            }
        }
        return filteredPostProcessors;
    }

遍历processors,如果是DestructionAwareBeanPostProcessor类型,通过requiresDestruction判断是否要求进行销毁:

    default boolean requiresDestruction(Object bean) {
        return true;
    }

requiresDestruction交由具体的DestructionAwareBeanPostProcessor子类去实现

总结

DisposableBeanAdapter总体流程比较清晰,代码浅显易懂,最后通过一个流程图来总结并巩固一下记忆:


DisposableBeanAdapter

相关文章

网友评论

      本文标题:Spring源码解析(十三)-DisposableBeanAda

      本文链接:https://www.haomeiwen.com/subject/ljapnhtx.html