Spring:java.lang.NoClassDefFoundError:无法初始化类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25701285/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 08:29:44  来源:igfitidea点击:

Spring: java.lang.NoClassDefFoundError: Could not initialize class

javaspringhibernatespring-mvc

提问by ars

I am developing a little web application in Spring MVC. I get the exception every time I try to get my custom class in any controller, in case if this class uses another custom class. It is easier to show on example:

我正在 Spring MVC 中开发一个小的 web 应用程序。每次我尝试在任何控制器中获取自定义类时都会收到异常,以防此类使用另一个自定义类。在示例中更容易显示:

Controller, where I'm trying to get an object of custom class WireTest:

控制器,我试图在其中获取自定义类 WireTest 的对象:

@Controller
@RequestMapping("/offices")
public class OfficesController {

  @Autowired
  private WireTest wt;

  @RequestMapping("")
  public String offices(Model model) {
    model.addAttribute("test", wt.getString());
    return "offices";
  }
}

The problem happens always, whether I'm creating an object directly or use @Autowired. In code here, I'm showing the case of @Autowired, but that doesn't matter - I could write private WireTest wt = new WireTest(), and the exception would be the same.

问题总是发生,无论我是直接创建对象还是使用@Autowired。在这里的代码中,我展示了@Autowired 的情况,但这无关紧要 - 我可以写private WireTest wt = new WireTest(),并且例外情况是一样的。

WireTest.javaclass:

WireTest.java班级:

@Service
public class WireTest {
  public String getString() {return (DBhelper.getString());}
}

Part of DBhelper.javaclass (There are also other static members, the full code is below):

部分DBhelper.java类(还有其他静态成员,完整代码如下):

public class DBhelper {
    public static String getString() {return "Hi!";}
}

And the exception:

和例外:

HTTP Status 500 - Handler processing failed; nested exception is         
java.lang.NoClassDefFoundError: Could not initialize class org.sher.wtpractice.dao.DBhelper

I also can use these classes without any problems in console application, so it works outside Spring.

我也可以在控制台应用程序中使用这些类而不会出现任何问题,因此它可以在 Spring 之外运行。

My Spring configuration:

我的弹簧配置:

web.xml:

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <!-- Processes application requests -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
</web-app>

dispatcher-servlet.xml:

dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<context:component-scan base-package="org.sher.wtpractice.spring, org.sher.wtpractice.dao" />
    <mvc:annotation-driven />
    <mvc:resources mapping="/css/**" location="/css/"/>
    <mvc:resources mapping="/js/**" location="/js/"/>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/jsp/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
</beans>

I'm using Maven for building and Tomcat 7 as a server, if that matters. Spring version is 4.0.1.RELEASE

如果重要的话,我正在使用 Maven 来构建和 Tomcat 7 作为服务器。Spring 版本是 4.0.1.RELEASE

Update: Complete code of DBhelper.java

更新:DBhelper.java 的完整代码

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

import java.util.Calendar;
import java.util.Date;
public class DBhelper {
    private static final SessionFactory sessionFactory = createSessionFactory();

    private static SessionFactory createSessionFactory() {
        Configuration configuration = new Configuration();
        configuration.configure();
        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(
                configuration.getProperties()).build();
        return configuration.buildSessionFactory(serviceRegistry);
    }

    public static Object queryWrapper(DBoperation op) {
        Session session = sessionFactory.openSession();
        Transaction transaction = null;
        Object result = null;
        try {
            transaction = session.beginTransaction();
            result = op.operation(session);
            session.getTransaction().commit();
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
//            throw e;
        } finally {
            if (session != null && session.isOpen())
                session.close();
        }
        return result;
    }
    public static Date normalizeCal(Calendar cal) {
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }
    public static String getString() {return "Hi!";}
}

Any help would be greatly appreciated!

任何帮助将不胜感激!

回答by Luke Woodward

Try lazy-loading the session factory instead of initializing it statically by assigning to a finalfield.

尝试延迟加载会话工厂,而不是通过分配给一个final字段来静态初始化它。

For example, create a method such as the following, which returns the session factory, creating it if necessary. Whenever you want to use the session factory, call this method instead of referring directly to the field:

例如,创建一个如下所示的方法,它返回会话工厂,必要时创建它。每当您想使用会话工厂时,请调用此方法而不是直接引用字段:

private static SessionFactory getSessionFactory() {
    if (sessionFactory == null) {
        sessionFactory = createSessionFactory();
    }
    return sessionFactory;
}

Personally I dislike static initialization for anything non-trivial, as you're out of control of when it happens. With the above method you are in control: the session factory gets created the first time you need to use it.

我个人不喜欢任何非平凡的静态初始化,因为你无法控制它何时发生。使用上述方法,您可以控制:会话工厂在您第一次需要使用时被创建。

If you want to know what the problem is, I have two suggestions. Firstly, restart your web application container and see if you get a different exception message first time. (The 'first time' is important here: Could not initialize classmeans that the JVM has already tried and failed to initialize the class.) Secondly, try wrapping the contents of the createSessionFactorymethod in a try-catchblock such as the following:

如果你想知道问题出在哪里,我有两个建议。首先,重新启动您的 Web 应用程序容器,看看您是否第一次收到不同的异常消息。(“第一次”在这里很重要:Could not initialize class意味着 JVM 已经尝试过初始化类但失败了。)其次,尝试将createSessionFactory方法的内容包装 在try-catch块中,如下所示:

try {
    ...
} catch (Throwable e) {
    e.printStackTrace();
    throw new RuntimeException(e);
}

However, I can't guarantee that either approach will offer you much enlightenment.

但是,我不能保证任何一种方法都会为您提供很多启发。

EDIT: rather than just speculate, I decided to actually try this out and see what happens. So I knocked up a small web application using Spring and Hibernate and deployed it to Tomcat. While attempting to get it working I encountered a few issues when attempting to read the Hibernate configuration, caused by me making the following mistakes:

编辑:而不是仅仅推测,我决定实际尝试一下,看看会发生什么。因此,我使用 Spring 和 Hibernate 构建了一个小型 Web 应用程序并将其部署到 Tomcat。在尝试让它工作时,我在尝试读取 Hibernate 配置时遇到了一些问题,这是由于我犯了以下错误:

  • I hadn't included the hibernate.cfg.xml file in the .war file,
  • I hadn't included the database's JDBC driver JAR in the .war file,
  • the database I was trying to connect to was down.
  • 我没有在 .war 文件中包含 hibernate.cfg.xml 文件,
  • 我没有在 .war 文件中包含数据库的 JDBC 驱动程序 JAR,
  • 我试图连接的数据库已关闭。

In each case my first approach worked. The first request made following a Tomcat restart gave me an ExceptionInInitializerErrorwith further details below it. The second and subsequent requests gave me NoClassDefFoundErrors which didn't tell me much about the problem.

在每种情况下,我的第一种方法都有效。Tomcat 重新启动后发出的第一个请求给了我一个ExceptionInInitializerError详细信息。第二个和随后的请求给了我NoClassDefFoundErrors,它没有告诉我很多关于这个问题的信息。

The problem is that once an ExceptionInInitializerErrorhas been thrown for a class, the JVM blacklists this class and will refuse to do anything with it subsequently. So you only get one chance to see what goes wrong in static initialization code. If you initialized Hibernate lazily as I recommended above, you would get the detailed exception message every time. Consider this another reason to avoid static initialization.

问题是一旦ExceptionInInitializerError一个类被抛出,JVM 就会将该类列入黑名单,并且随后将拒绝对其进行任何操作。因此,您只有一次机会看到静态初始化代码中出了什么问题。如果你像我上面推荐的那样懒惰地初始化 Hibernate,你每次都会得到详细的异常消息。考虑这是避免静态初始化的另一个原因。

回答by Loki

Check the static initialization of DBhelper.

检查 的静态初始化DBhelper

"NoClassDefFoundError: Could not initialize class" error

“NoClassDefFoundError:无法初始化类”错误

In this case, instantiate sessionFactoryas spring bean, and let the spring container assemble it to DBhelper.

这种情况下,实例sessionFactory化为spring bean,让spring容器组装成DBhelper.