Spring: Bean-Initialisierung in einem Webprojekt -> NullPointerException

Wilde

Grünschnabel
Spring: Bean-Instanziierung in einem Webprojekt -> NullPointerException

Hallo,

ich möchte eine Webapplikation mit Spring und Hibernate schreiben. Die Webapplikation läuft im Tomcat. Zum Testen habe ich ein einfaches Servlet und ein DAO angelegt. Außerdem habe ich die web.xml und applicationContext.xml entsprechend aufgesetzt.

Und nun zum Problem... Wenn ich das Servlet aufrufe, dann habe ich in der doGet() den DAO-Aufruf. Jedesmal, wenn diese Zeile Code aufgerufen wird, erhalte ich eine NullPointerException. Grund hierfür ist aus meiner Sicht, dass das DAO-Bean nicht instanziiert wurde.

Im Folgenden möchte ich euch den Quellcode und die XMLs zeigen:

Servlet:
Code:
public class TestServlet extends HttpServlet {
	
	public TestDAO testDAO;
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("doGet");
		testDAO.create();
	}

	// Spring setter
	public void setTestDAO(TestDAO testDAO) {
		this.testDAO= testDAO;
	}
}

DAO Interface:
Code:
public interface TestDAO {
	public void create();
}

DAO Impl:
Code:
public class TestDAOImpl extends HibernateDaoSupport implements TestDAO {

	public void create() {
                System.out.println("TestDAOImpl");
	}
}

web.xml
Code:
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">

  <display-name>testSpring</display-name>

  	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
 	</welcome-file-list>
 
  	<!-- Spring -->
  	<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:applicationContext.xml
        </param-value>
    </context-param>
    
    <!-- Spring listener -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
    
  	<servlet>
    	<description></description>
   		<display-name>TestServlet</display-name>
    	<servlet-name>TestServlet</servlet-name>
    	<servlet-class>test.TestServlet</servlet-class>
  	</servlet>
  	<servlet-mapping>
    	<servlet-name>TestServlet</servlet-name>
    	<url-pattern>/TestServlet</url-pattern>
  	</servlet-mapping>
</web-app>

applicationContext.xml
Code:
<beans>
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName"><value>org.apache.derby.jdbc.ClientDriver</value></property>
        <property name="url"><value>jdbc:derby://localhost:1527/testDB</value></property>
        <property name="username"><value>***</value></property>
        <property name="password"><value>***</value></property>
    </bean>

    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="annotatedClasses">
			<list>
				<value>test.vo.TestVO</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop>
				<prop key="hibernate.hbm2ddl.auto">create</prop>
			</props>
		</property>
	</bean>
    
	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

	<bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
		<property name="transactionManager" ref="transactionManager"/>
	</bean>

	<bean id="testDAO" class="test.dao.TestDAOImpl">
		<property name="sessionFactory" ref="sessionFactory"/>
	</bean>
</beans>

Wenn der Tomcat startet, kann ich in den Logs sehen, dass eine Pre-Instanziierung des DAOs stattgefunden hat.
Code:
[..]
30.09.2008 21:22:04 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@127461b: defining beans [dataSource,sessionFactory,transactionManager,transactionTemplate,kundeDAO]; root of factory hierarchy
[..]


Vielleicht weiß jemand von euch, wieso ich jedesmal eine NullPointerException erhalte bzw wieso das DAO nicht instanziiert ist.
 
Zuletzt bearbeitet:
Das DAO ist instatiiert. Du hast nur einen kleinen Denkfehler gemacht. Servlets stehen unter der Kontrolle des Containers, also Tomcat. Spring kann nur Dependencies in Objekte injizieren, die als Springbeans deklariert werden. Es gibt zwar eine Möglichkeit in Servlets an den ApplicationContext zu kommen, allerdings widerspricht der dem DependencyInjection Prinzip.

Wenn du es mal genau durchdenkst... wo hast du denn konfiguriert, dass Spring dem Servlet das DAO injizieren soll? ;) Es kann einfach nicht funktionieren.

Die richtige Vorgehensweise wäre folgende: Du registrierst das DispatcherServlet (Spring Klasse) in der web.xml. Dies sorgt dafür dass für ein Konfigurationsfile WEB-INF/${servletname}-context.xml geladen wird. Dann benötigst du anstelle des Servlet eine Klasse die das Interface org.springframework.web.servlet.mvc.Controller implementiert. Die Logik aus deinem doGet kann dann in die Methode handle(Request, Response). Diese Klasse registrierst du als bean in dem ${servletname}-context.xml und konfigurierst da das Setzen des DAOs. Um die Controller bean an eine URL zu binden, gibst du z.B. "/foo" als namen bzw. id.

Ein paar Kleinigkeiten noch:
Wozu konfigurierst du das Transactiontemplate?
Wozu konfigurierst du den RequestContextListener?
Aus deiner Hibernatekonfiguration lässt sich schließen, dass du die zu persistierenden Objekte ValueObjects nennst (VO). Damit wäre ich vorsichtig - was du vermutlich eher persistierst sind Entities. Namensgebung ist hierbai nicht ganz unerheblich da diese Namen mit wohldefinierten Konzepten verbunden sind und es so zu Missverständnissen kommen kann, wenn sich die Konzepte dann nicht in der Implementierung wiederspiegeln.

Grundsätzlich würde ich - wenn ich auf der grünen Wiese starte - versuchen, eher auf JPA zu setzen als auf Hibernate. Gerade wenn man Annotationen benutzt, landen diese meist im Domänenmodell. Da ist es dann günstiger Standardisierte Annotationen zu verwenden anstatt proprietäre, da sonst dein Domänenmodell von Hibernate abhängt. Du kannst ja Hibernate auch Problemlos als Persistenzprovider für eine JPA basierte DAO Implementierung benutzen. Du reduzierst dadurch die Abhängigkeit deines Codes zu einer Technologie.

Gruß
Ollie
 

Neue Beiträge

Zurück