问题
Question is not a duplicate as Hibernate is involved
As the James' answer partially solved the problem, I accepted it and opened a new question, please follow up here
I am trying to inject SessionFactory into a repository class; however, it looks like it does not work as the code returns NullPointer exception. I cleaned and rebuilt the project but the issue still exist. I also put @Autowired on the setSessionFactory method but did not help.
Interface
public interface TestRep {
public void get(int id);
}
Class
@Repository
public class TestRepImpl implements TestRep{
@Autowired
SessionFactory sessionFactory;
public TestRepImpl() {
}
public TestRepImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Transactional
public void get(int id) {
String hql = "from Business where id=" + id;
Query query = sessionFactory.getCurrentSession().createQuery(hql);
....
pr-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<context:annotation-config/>
.....
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="TestRep" class="com.project.repository.TestRepImpl">
<constructor-arg>
<ref bean="sessionFactory" />
</constructor-arg>
</bean>
StackTrace
Mar 10, 2015 12:22:21 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [pr] in context with path [/project] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException
at com.project.repository.TestRepImpl.get(TestRepImpl.java:39)
at com.project.web.MainController.index(MainController.java:17)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1074)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:314)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Jars

MainController
@Controller
public class MainController {
@RequestMapping("/{viewName}.htm")
public String index(@PathVariable(value = "viewName") String viewName) {
System.err.println(viewName);
Test test = new Test();
test.get(1);
if (isValidView(viewName)) {
return viewName;
}
return null;
}
@RequestMapping("/{viewName}/{viewName2}") //suburb/catname
public String index(@PathVariable(value = "viewName") String viewName, Model model) {
System.err.println(viewName);
if (isValidView(viewName)) {
model.addAttribute("viewName",viewName);
return "page";
}
return null;
}
private boolean isValidView(String viewName) {
switch (viewName) {
case "index":
case "aboutus":
return true;
}
return false;
}
}
Test
@Service
public class Test {
public void get(int i){
TestRepImpl test = new TestRepImpl();
test.get(i);
}
}
Hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">12</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">update</property>
<mapping class="com.myproject.model.MyTable" />
....
回答1:
You need to use Autowiring everywhere or your program won't work. Spring can only autowire beans that are present in the Spring application context, which is what your @Controller
, @Service
and @Repository
annotations are supposed to do. However, these annotations are meaningless without a <context:component-scan base-package="your.base.package">
tag in your config XML.
So, assuming that your controller, service and DAO are all somewhere in the package com.repository
, you need to add this line to your XML config.
<context:component-scan base-package="com.repository"/>
What this does is tells Spring to recursively search inside the foo.bar.baz package (and all sub-packages) for classes annotated with @Controller
, @Service
, @Repository
and @Component
, instantiate a singleton instance of them and make them eligible to be autowired into other classes.
You also need to modify your controller and service classes to use @Autowired
. Spring can't manage your classes if you instantiate them with the new
keyword. These beans are singletons (only one instance of them should ever exist in your program) for a reason.
Your controller needs to change as follows.
@Controller
public class MainController {
@Autowired
private TestService testService;
@RequestMapping("/{viewName}.htm")
public String index(@PathVariable(value = "viewName") String viewName) {
System.err.println(viewName);
testService.get(1);
if (isValidView(viewName)) {
return viewName;
}
return null;
}
@RequestMapping("/{viewName}/{viewName2}") //suburb/catname
public String index(@PathVariable(value = "viewName") String viewName, Model model) {
System.err.println(viewName);
if (isValidView(viewName)) {
model.addAttribute("viewName",viewName);
return "page";
}
return null;
}
private boolean isValidView(String viewName) {
switch (viewName) {
case "index":
case "aboutus":
return true;
}
return false;
}
}
Notice that you Autowire your service class into your controller.
Your service class needs to implement an interface. Spring does all this autowiring magic using interfaces. You cannot autowire a class that does not implement an interface, unless you specifically create an instance of that class in your XML config.
Your service class needs to change as follows:
@Service
public class TestServiceImpl implements TestService {
@Autowired
private TestRepDao testDao;
@Transactional
public void get(int i){
testDao.get(i);
}
}
and create an interface called TestService.
public interface TestService{
public void get(int i);
}
and then your DAO becomes
@Repository
public class TestRepDaoImpl implements TestRepDao{
@Autowired
private SessionFactory sessionFactory;
public void get(int id) {
String hql = "from Business where id=" + id;
Query query = sessionFactory.getCurrentSession().createQuery(hql);
}
}
which implements the interface TestRepDao:
public interface TestRepDao{
public void get(int id);
}
you can also remove the declaration of
<bean id="TestRep" class="com.project.repository.TestRepImpl">
<constructor-arg>
<ref bean="sessionFactory" />
</constructor-arg>
</bean>
from your XML configuration.
As you can see I've changed a few class names to better fit with the Spring convention. Your application is supposed to layer down from Controller to Service Class to DAO and back out again. This should work providing you follow the steps I've laid out here.
A few things to keep in mind:
- Spring hates the
new
keyword. If you find yourself using it, you are probably doing something wrong. - There is only ever one instance of any of your classes that Spring picks up with the component scan in your entire application. DO NOT use these classes to store persistent data or states. That path is full of threading issues, race conditions and pits full of acid spiders.
- Read and re-read the documentation, these are not easy concepts to pick up if you have never used Spring before. Spring is super easy to use, once you understand how it works, and how it expects you to use it.
- Spring works on interfaces. If your class doesn't implement an interface, Spring can't proxy it without using AspectJ Load Time Weaving, which is a conversation for another day, and not something you should be using, just starting out. If you don't know why Spring needs to create a proxy of your object, you need to re-read the documentation until you understand the application context.
- I moved the
@Transactional
annotation into the Service class. This is because the DAO should only be concerned with accessing and retrieving the data from the database, NOT having to manage the connection/session to the database, that is the job of the service class. I'm guessing you started using the
new
keyword after hitting exceptions saying something similar toNo qualifying bean of type found for dependency TestService.
This is Spring telling you that it doesn't have a bean that can be autowired into the TestService field on whatever class. Listen when Spring is telling you things, it will save you a lot of bother.
- Don't be discouraged, I faced all these problems when I was trying to learn how to use Spring, but I got through it and Spring is second nature to me now.
来源:https://stackoverflow.com/questions/28955754/spring-4-1-5-release-fails-to-do-dependency-injection-for-sessionfactory-of-hibe