【问题标题】:After upgrading to Spring Boot 1.4.0, NullPointerException in AbstractPlatformTransactionManager升级到 Spring Boot 1.4.0 后,AbstractPlatformTransactionManager 中出现 NullPointerException
【发布时间】:2016-12-04 18:55:26
【问题描述】:

我已从 Spring Boot 1.3.2 升级到 1.4.0,现在无法启动我的应用程序 - 我的 BeanPostProcessor 调用了 3d 派对开源 Lazy Chopper,而当尝试 getTransaction() 时,它又在这里失败了:

public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {

    protected transient Log logger = LogFactory.getLog(getClass());
    // ...
    @Override
    public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
        Object transaction = doGetTransaction();

        // Cache debug flag to avoid repeated checks.
        boolean debugEnabled = logger.isDebugEnabled(); // logger is null here

当我在此处放置断点时,我可以看到 logger 确实是 null,但如果值得一提的是,如果我自己在那里调用 LogFactory.getLog(getClass()),我确实得到了正确的记录器。

似乎我的 bean 在初始化正确的 Logger 之前以某种方式调用了该方法?..

这是我得到的完整堆栈跟踪:

Caused by: java.lang.NullPointerException: null
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:340) ~[spring-tx-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:426) ~[spring-tx-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:275) ~[spring-tx-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at com.tikal.lazychopper.DefaultLazyInitializationChopperAdvice.chop(DefaultLazyInitializationChopperAdvice.java:76) ~[lazy-chopper-1.2.8.jar:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_101]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_101]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_101]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_101]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at com.sapiens.bdms.core.service.impl.sign.hash.MD5StringCalculator$$EnhancerBySpringCGLIB$$b5747fb.getSignTypes(<generated>) ~[classes/:na]
at com.sapiens.bdms.core.service.impl.sign.EntitySignCalculatorManagerImpl.postProcessAfterInitialization(EntitySignCalculatorManagerImpl.java:105) ~[classes/:na]
at com.sapiens.bdms.core.service.impl.sign.EntitySignCalculatorManagerImpl$$FastClassBySpringCGLIB$$80ef4d8e.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at com.sapiens.bdms.core.service.impl.sign.EntitySignCalculatorManagerImpl$$EnhancerBySpringCGLIB$$91a9897b.postProcessAfterInitialization(<generated>) ~[classes/:na]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:422) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1583) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]

我使用默认的logback 自动配置,没有任何调整。

更新 #1: 围绕该方法定义了切入点。

            <aop:pointcut id="transactionManagerPointcut"
                      expression="(execution(* org.springframework.transaction.PlatformTransactionManager.getTransaction(..)))"/>

更新 #2: 所以似乎摆脱这方面的伎俩..仍在试图弄清楚为什么以及如何克服这一点。

这是方面的定义:

            <aop:pointcut id="transactionManagerPointcut"
                      expression="(execution(* org.springframework.transaction.PlatformTransactionManager.getTransaction(..)))"/>

        <aop:pointcut id="allServices"
                      expression="(execution(* com.decision..tx..*.*(..))) or (execution(* com.sapiens.bdms..tx..*.*(..))) &amp;&amp; !@annotation(com.sapiens.bdms.core.persistence.annotation.NotTransactional)"/>
        <aop:aspect ref="sessionFilterConfigurator">
            <aop:before method="setupFilter"
                        pointcut-ref="allServices"/>
            <aop:after-returning method="setupFilter"
                                 pointcut-ref="transactionManagerPointcut"/>
        </aop:aspect>

这是方面的方法:

    @Component("sessionFilterConfigurator")
public class SessionFilterConfigurator {
    @Resource
    private Collection<FilterConfiguration> filterConfigurations;
    @Resource
    private SessionFactory sessionFactory;
    @Resource
    private FiltersDisconnector filtersDisconnector;

    public void setupFilter() throws Throwable {
        Session session = sessionFactory.getCurrentSession();
        if (AutoEnableConfig.isFiltersEnabled()) {
            for (FilterConfiguration filterConfiguration : filterConfigurations) {
                Filter filter = session.enableFilter(filterConfiguration.getFilterName());
                for (Map.Entry<String, Object> entry : filterConfiguration.getFilterParameters().entrySet()) {
                    filter.setParameter(entry.getKey(), entry.getValue());
                }
            }
            AutoEnableConfig.disableFilterEnabling();
            ((EventSource) session).getActionQueue().registerProcess(filtersDisconnector);
        }
    }
}

仍然不清楚为什么在这种情况下会破坏记录器,以及为什么只有在升级到 1.4.0 之后...

【问题讨论】:

  • NPE 很奇怪。 logger 在构造时初始化并且不会再次分配,除非对象从序列化中恢​​复。但是该字段受到保护,因此子类可能会将其设置为null。在 Spring Framework 中没有代码这样做,因此它必须在该扩展中。我很困惑为什么它会这样做以及为什么它会在更新时中断。那个特定的班级根本没有改变。你能分享一个重现问题的样本吗?
  • @StéphaneNic​​oll 感谢您的及时回复。我同意。这很奇怪 - 我的想法是,没有人用 null 覆盖它,而是可能出于某种特殊原因,LogFactory 实际上返回 null.. 与记录器实现的不匹配有关?..这听起来像是一个公平的评估?..我想也许在这里发布依赖关系树。你认为这有帮助吗?
  • @StéphaneNic​​oll 也值得一提,为该服务定义了切入点。见上面的编辑
  • @StephaneNic​​oll 我有同样的问题,但在AbstractRememberMeServices。请参阅此评论:github.com/jhipster/generator-jhipster/issues/…。你能帮我解决这个问题吗?

标签: spring logging spring-boot logback slf4j


【解决方案1】:

我遇到了同样的问题。我的错是由于错误的切入点定义,我最终将切面应用到了 TransactionManager 上(我扩展了标准切入点)。所以空记录器是 CGLIB 生成的扩展类之一。真正的 bean 很好地实例化了它的记录器。

【讨论】:

  • 感谢您的回答。没有完全明白你做了什么来解决它?..我已经发现它与 CGLIB 生成的扩展类最相关。你能绕过它吗?
  • 我可以通过环绕 org.springframework.orm.hibernate5.HibernateTransactionManager 而不是 org.springframework.transaction.PlatformTransactionManager 来解决它。缺点很明显......但我不知道如何解决这个问题......至少现在还没有。
  • 我更正了我的方面,不要环绕事务管理器。对于所有带有事务的自定义内容,我扩展了标准事务管理器,而不是使用方面拦截对它的调用。
  • 你的评论让我很困惑。您是否仍在使用 Aspect,或者改为扩展事务管理器。你说“更正”,但接着说你扩展而不是拦截……就是这样。 @ronif - 你还有什么想出的吗?
  • Jason,我不再将 Aspect 应用于 TransactionManager。但是,我确实使用了扩展的 TransactionManager 来为其添加自定义逻辑(就像应用了方面一样)。
【解决方案2】:

我也遇到过这个问题。就我而言,我只是启用了 Spring 方面工具并构建了项目。它奏效了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-16
    • 2016-12-23
    • 2017-01-13
    • 2019-01-13
    • 2021-09-06
    • 1970-01-01
    相关资源
    最近更新 更多