乐趣区

关于springboot:Spring-boot-如果一个serivice-Transactional所在方法不是public会发生什么

咱们先说如果该办法是 public,钻研一下其中的细节

@Service
public class TestServiceImpl {@Transactional(rollbackFor = Exception.class)
    public void trans1(){}
}


AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(), 其中 applyBeanPostProcessorsAfterInitialization()继承自 AbstractAutoProxyCreator,上面是办法细节

    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        //getBeanPostProcessors()是 sptring boot 启动时系统配置的 BeanPostProcessor;其中有一个 BeanPostProcessor 叫做 AnnotationAwareAspectJAutoProxyCreator;for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {// 当遍历 AnnotationAwareAspectJAutoProxyCreator 时,执行其 postProcessAfterInitialization()
            Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
            if (current == null) {return result;}
            result = current;
        }
        return result;
    }

以下是 AbstractAutoProxyCreator.postProcessAfterInitialization()细节:

    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (!this.earlyProxyReferences.contains(cacheKey)) {
                // 这个办法的重要逻辑是,依据 beanName 获取告诉列表,如果列表不为空,创立代理类;return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

图 2
图 3

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        // 获取 bean 和 beanName 获取告诉列表.
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        // 本示例中 testServiceImpl 的 specificInterceptors 如图 2 所示;// 如果告诉列表不为空,则创立代理类
        if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 执行具体创立代理逻辑,本示例中 testServiceImpl 的 specificInterceptors 如图 3 所示
            Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            // 间接返回
            return proxy;
        }
        // 如果没有匹配的告诉列表,返回一般的 bean
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;

}

如果咱们测试用例中的 public 去掉呢?,咱们间接贴出后果:
图 4
能够看到 specificInterceptors = null, 也就是说并没有为其生成代理类。什么起因呢?咱们持续往下看:

    //candidateAdvisors 来自 spring boot 启动是配置的告诉列表
    protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {ProxyCreationContext.setCurrentProxiedBeanName(beanName);
        try {// 由 AopUtils.findAdvisorsThatCanApply()执行具体的匹配逻辑
            return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
        }
        finally {ProxyCreationContext.setCurrentProxiedBeanName(null);
        }
    }

咱们能够看到候选的告诉列表有 24 个
图 5

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
        if (methodMatcher instanceof IntroductionAwareMethodMatcher) {introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
        }

        Set<Class<?>> classes = new LinkedHashSet<>();
        if (!Proxy.isProxyClass(targetClass)) {classes.add(ClassUtils.getUserClass(targetClass));
        }
        classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

        for (Class<?> clazz : classes) {Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
            for (Method method : methods) {
                // 因为 introductionAwareMethodMatcher == null, 所以 methodMatcher.matches 理论执行咱们的候选告诉器 match 办法;if (introductionAwareMethodMatcher != null ?
                        introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                        methodMatcher.matches(method, targetClass)) {return true;}
            }
        }

        return false;
}

图 6
以 TransactionAttributeSourcePointcut.matches()为例:
图 7

public boolean matches(Method method, @Nullable Class<?> targetClass) {if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {return false;}
        // 图 7 为 tas 实例
        TransactionAttributeSource tas = getTransactionAttributeSource();
        return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
    }
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    // We need to work it out.
    TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
        return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

tas.getTransactionAttribute()会调用 AbstractFallbackTransactionAttributeSource.computeTransactionAttribute():

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
        // Don't allow no-public methods as required.
        // 通过下面这个正文看出不容许非 public,因而返回 null;
        if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {return null;}
}

此时下面的 matches()返回 false, 最终 AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass)返回空列表,这样一来 AbstractAutoProxyCreator.wrapIfNecessary()中的 specificInterceptors 变量为 null,也就没有方法创立代理类了!

最初,再抛出一个问题,如果一个 service @Transactional 办法既有 public, 又有 no-pubic 会怎么呢?欢送一起探讨~~~

退出移动版