2014-09-06 9 views
3

Spring MVC에서 작은 웹 애플리케이션을 개발 중입니다. 이 클래스가 다른 사용자 정의 클래스를 사용하는 경우 모든 컨트롤러에서 사용자 정의 클래스를 가져 오려고 할 때마다 예외가 발생합니다. 이 예에 표시하는 것이 더 쉽습니다 :Spring : java.lang.NoClassDefFoundError : 클래스를 초기화 할 수 없습니다.

나는 사용자 정의 클래스의 객체를 얻으려고 컨트롤러, WireTest : 내가 직접 사용하거나 개체를 만드는거야 여부 문제는 항상 발생

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

    @Autowired 
    private WireTest wt; 

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

을 @Autowired. 여기 코드에서는 @Autowired의 경우를 보여 드리지만, 중요하지 않습니다. private WireTest wt = new WireTest()을 쓸 수 있으며 예외는 동일합니다.

WireTest.java 클래스 :

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

DBhelper.java 클래스 (이 다른 정적 멤버는 또한, 전체 코드는 다음과 같습니다)의 일부 :

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

그리고 예외 :

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

콘솔 앱에서도 문제없이 이러한 클래스를 사용할 수 있습니다. 연화, 그래서 그것은 봄 바깥에서 작동합니다.

내 스프링 구성 :

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 : 그 중요한 경우 내가 서버로 건물 메이븐과 톰캣 7을 사용하고

<?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> 

. 봄 버전은 4.0.1.RELEASE

업데이트입니다 : 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!";} 
} 

의 전체 코드가 어떤 도움을 크게 감상 할 수있다!

+0

DBhelper 클래스가 jar 파일의 일부입니까? – zerocool

+0

아니요. DBhelper와 WireTest 클래스 간의 이러한 관점과 유일한 차이점은 서로 다른 패키지에 위치한다는 것입니다. WireTest는 한 단계 더 깊습니다. – ars

+0

war 파일의 압축을 풀고이 클래스가 war의 일부로 maven에 패키지되었는지 확인할 수 있습니까? – zerocool

답변

4

final 필드에 할당하여 정적으로 초기화하는 대신 세션 팩토리를 지연로드 해보십시오.

예를 들어 세션 팩토리를 리턴하는 다음과 같은 메소드를 작성하여 필요한 경우 작성하십시오. 당신이 세션 팩토리를 사용할 때마다 대신 필드에 직접 참조하는이 메서드를 호출 : 당신이 일어날 때의 통제에서있는 한

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

는 개인적으로 내가 아닌 사소한 아무것도 정적 초기화를 싫어한다.위 메소드를 사용하면 제어 할 수 있습니다. 세션 팩토리는 처음 사용할 때 만들어집니다.

문제가 무엇인지 알고 싶다면 두 가지 제안이 있습니다. 먼저 웹 응용 프로그램 컨테이너를 다시 시작하고 처음으로 다른 예외 메시지가 표시되는지 확인합니다. 합니다 ('처음'여기서 중요하다 : Could not initialize class는 JVM 이미 시도 클래스를 초기화하지 못한 것을 의미한다.) 둘째하는 trycreateSessionFactory 방법의 내용을 배치하려고 - 다음과 같은 catch 블록 :

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

그러나 두 방법 중 하나를 사용하면 많은 깨달음을 제공 할 수 있다고 보장 할 수 없습니다.

EDIT : 추측보다는 실제로 이것을 시도하고 어떤 결과가 발생하는지 확인하기로했습니다. 그래서 Spring과 Hibernate를 사용하여 작은 웹 어플리케이션을 만들어서 Tomcat에 배포했습니다. 나는 .war 파일에있는 hibernate.cfg.xml 파일을 포함하지 않은

  • : 제대로 작동 얻을하는 동안 나에게 다음과 같은 실수에 의한 최대 절전 모드 구성을 읽으려고 할 때 나는 몇 가지 문제가 발생 ,
  • 데이터베이스의 JDBC 드라이버 JAR을 .war 파일에 포함시키지 않았습니다.
  • 연결하려는 데이터베이스가 다운되었습니다.

각각의 경우 첫 번째 접근 방식이 적용되었습니다. Tomcat을 다시 시작한 후 처음으로 요청한 내용은 ExceptionInInitializerError이고 그 아래 세부 정보가 나와 있습니다. 두 번째 및 후속 요청은 내게이 문제에 대해 많이 말하지 않은 NoClassDefFoundError을 제공했습니다.

ExceptionInInitializerError이 클래스에 대해 던져지면 JVM이이 클래스를 블랙리스트에 추가하고 이후에 아무 것도하지 않는 것이 문제입니다. 따라서 정적 초기화 코드에서 무엇이 잘못되는지 한 번만 볼 수 있습니다. 위에서 권장 한대로 lazily로 Hibernate를 초기화했다면 매번 상세한 예외 메시지를 얻을 것이다. 정적 초기화를 피하는 또 다른 이유를 고려하십시오.

+0

지난 몇 시간 동안 Spring에서 모든 Hibernate 코드를 다시 작성했다. bean, autowiring 및 데이터베이스 연결이 web.xml에 선언되어있다. (솔직히, 나는 왜 Spring 개발자가 그렇게하리라고 생각하는지 모르겠다.) 도움이되지는 않았지만 오류는 다릅니다. Tomcat이 애플리케이션을 시작할 수 없습니다. 그래서 로그를 살펴보고 Tomcat이 JDBC 드라이버를 찾을 수 없다는 것을 알게되었습니다. 일부 인터넷 검색을 한 후 Tomcat이 JDBC 드라이버를 검색한다는 사실을 알게되었습니다. WAR 파일이 아닌 자체 lib 폴더에 문제가 해결되었습니다. – ars

+0

귀하의 추천에 감사드립니다. 내'createSessionFactory'가 게으른 스타일로 작성 되었다면, 예외가 그 이유를 알기에 충분할만큼 웅변적일 것이므로 문제는 즉시 해결 될 것이라고 생각합니다. 그래서 당신의 대답을 받아 들였습니다. – ars

0

정적 초기화 DBhelper을 확인하십시오. 이 경우

"NoClassDefFoundError: Could not initialize class" error

, 스프링 빈으로 sessionFactory를 인스턴스화하고, 스프링 컨테이너가 DBhelper에 조립하자.

+0

글쎄, 나는 매우 새롭다. 봄, 그리고 이것을 어떻게하는지 잘 이해하지 못합니다. 정적 인 마지막 SessionFactory 객체를 가지고 별도의 클래스를 만들어서 Bean (@Service)으로 표시하고 DBhelper에 autowire할까요? 또한 Spring 피쳐로 인해 Hibernate와 관련된 코드를 왜 변경해야하는지 이해할 수 없다. 더 우아한 방법이 있습니까? 보통 사람들이 이것을 어떻게 처리합니까? – ars

+0

봄 - 최대 절전 모드 질문에 대한 귀하의 링크는 정말 도움이됩니다, 나는 거기서 같이하려고 노력할 것입니다. 그러나 나는 아직도 문제의 핵심을 얻지 못한다. 왜 Spring은 간단한 콘솔 어플리케이션이 할 수없는 일을 할 수 있습니까? – ars

+0

최대 절전 모드 등은 항상 구성이 필요하므로 스프링 IoC는 비즈니스 코드에서 구성을 추출합니다. 그것에 관한 몇 가지 문서를 읽을 수 있습니다. http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html – Loki

관련 문제