我正在为我创建的数据库编写一个小的 Web 界面。数据库访问是通过 Hibernate 完成的,但它也使用 Spring 来注入 DAO 的实例(这反过来又注入了 SessionFactory)。我在嵌入式 Jetty 服务器上测试 Web 界面。独立使用时一切正常:我可以从数据库项目中获取数据库中的内容,我可以在 Jetty 服务器上使用 Wicket 运行网页,我什至设法让 Spring 为 WicketTester 工作,这有点痛苦在屁股。但是现在当我尝试从数据库中获取某些内容时(通过单击网页上的某个按钮),我收到一条错误消息:
java.lang.NullPointerException
at nl.ru.cmbi.pdbeter.core.controller.DAO.GenericDAO.getCurrentSession(GenericDAO.java:37)
不知何故,应该在 DAO 中注入的 sessionFactory 没有被注入。我在 Wicket 模块的 applicationContext.xml 中定义了 DAO bean,但我认为只要它看到 SessionFactory 的 @Autowired,它就会在该项目的 spring.xml 文件中查找,但显然不是。我将在下面放置一些代码来展示各个部分的工作情况。
检票应用:
@Service
public class WicketApplication extends WebApplication {
@SpringBean
private IPDBEntryDAO pdbEntryDAO;
public IPDBEntryDAO getPdbEntryDAO() {
return pdbEntryDAO;
}
public void setPdbEntryDAO(IPDBEntryDAO pdbEntryDAO) {
this.pdbEntryDAO = pdbEntryDAO;
}
/**
* @see org.apache.wicket.Application#getHomePage()
*/
@Override
public Class<HomePage> getHomePage() {
return HomePage.class;
}
/**
* @see org.apache.wicket.Application#init()
*/
@Override
public void init() {
super.init();
new ClassPathXmlApplicationContext("applicationContext.xml").getAutowireCapableBeanFactory().autowireBean(this);
}
public void setupInjector() {
getComponentInstantiationListeners().add(new SpringComponentInjector(this));
}
}
启动嵌入式 Jetty 服务器的类(复制自 Wicket 快速入门):
public class Start {
public static void main(String[] args) throws Exception {
int timeout = (int) Duration.ONE_HOUR.getMilliseconds();
Server server = new Server();
SocketConnector connector = new SocketConnector();
// Set some timeout options to make debugging easier.
connector.setMaxIdleTime(timeout);
connector.setSoLingerTime(-1);
connector.setPort(8080);
server.addConnector(connector);
// check if a keystore for a SSL certificate is available, and
// if so, start a SSL connector on port 8443. By default, the
// quickstart comes with a Apache Wicket Quickstart Certificate
// that expires about half way september 2021. Do not use this
// certificate anywhere important as the passwords are available
// in the source.
Resource keystore = Resource.newClassPathResource("/keystore");
if (keystore != null && keystore.exists()) {
connector.setConfidentialPort(8443);
SslContextFactory factory = new SslContextFactory();
factory.setKeyStoreResource(keystore);
factory.setKeyStorePassword("wicket");
factory.setTrustStoreResource(keystore);
factory.setKeyManagerPassword("wicket");
SslSocketConnector sslConnector = new SslSocketConnector(factory);
sslConnector.setMaxIdleTime(timeout);
sslConnector.setPort(8443);
sslConnector.setAcceptors(4);
server.addConnector(sslConnector);
System.out.println("SSL access to the quickstart has been enabled on port 8443");
System.out.println("You can access the application using SSL on https://localhost:8443");
System.out.println();
}
WebAppContext bb = new WebAppContext();
bb.setServer(server);
bb.setContextPath("/");
bb.setWar("src/main/webapp");
// START JMX SERVER
// MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
// MBeanContainer mBeanContainer = new MBeanContainer(mBeanServer);
// server.getContainer().addEventListener(mBeanContainer);
// mBeanContainer.start();
server.setHandler(bb);
try {
System.out.println(">>> STARTING EMBEDDED JETTY SERVER, PRESS ANY KEY TO STOP");
server.start();
System.in.read();
System.out.println(">>> STOPPING EMBEDDED JETTY SERVER");
server.stop();
server.join();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
web.xml 文件:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app 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"
version="2.5">
<display-name>web-interface</display-name>
<!--
There are three means to configure Wickets configuration mode and they
are tested in the order given.
1) A system property: -Dwicket.configuration
2) servlet specific <init-param>
3) context specific <context-param>
The value might be either "development" (reloading when templates change) or
"deployment". If no configuration is found, "development" is the default. -->
<filter>
<filter-name>wicket.web-interface</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationClassName</param-name>
<param-value>nl.ru.cmbi.pdbeter.WicketApplication</param-value>
</init-param>
<init-param>
<param-name>applicationFactoryClassName</param-name>
<param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
</init-param>
<init-param>
<param-name>applicationBean</param-name>
<param-value>wicketApplication</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>wicket.web-interface</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- The SpringWebApplicationFactory will need access to a Spring Application context, configured like this... -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
applicationContext.xml 文件:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<!--
<context:component-scan base-package="nl.ru.cmbi.pdbeter" />
-->
<!-- setup wicket application -->
<bean id="wicketApplication" class="nl.ru.cmbi.pdbeter.WicketApplication">
<property name="pdbEntryDAO" ref="pdbEntryDAO"/>
</bean>
<bean id="pdbEntryDAO" class="nl.ru.cmbi.pdbeter.core.controller.DAO.PDBEntryDAO" />
</beans>
来自数据库模块的 DAO 类的一部分:
public class GenericDAO<I> implements IGenericDAO<I> {
private Class<I> persistentClass;
@Autowired
private SessionFactory sessionFactory;
@SuppressWarnings("unchecked")
public GenericDAO() {
persistentClass = (Class<I>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
protected Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
数据库模块使用的spring.xml文件:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<context:component-scan base-package="nl.ru.cmbi.pdbeter" />
<!-- Transaction Manager -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven />
<!-- Session Factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="hibernate.cfg.xml" />
<property name="packagesToScan" value="nl.ru.cmbi.pdbeter.core.model.domain" />
</bean>
</beans>
很抱歉发布了这么多代码,但我想如果我不这样做,我可能会泄露重要的东西。
有谁知道如何确保 Wicket 模块和数据库模块的所有内容都被注入?