我正在开发小应用程序并且在DI方面存在一些问题。
我有一个存储库类用于保存我注入到我的服务中的实体。我想使用H2K向它注入Session对象。 为此,我尝试执行以下SO帖子中描述的类似内容:
所以我创建了SFFactory类并在ApplicationConfig中注册它。
SFFactory.java
import org.glassfish.hk2.api.Factory;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class SFFactory implements Factory<Session> {
private SessionFactory factory;
public SFFactory() {
Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
StandardServiceRegistryBuilder srBuilder = new StandardServiceRegistryBuilder();
srBuilder.applySettings(configuration.getProperties());
factory = configuration.buildSessionFactory(srBuilder.build());
}
@Override
public Session provide() {
return factory.openSession();
}
@Override
public void dispose(Session session) {
if (session.isOpen()) {
session.close();
}
}
}
ApplicationConfig.java
import org.alexdzot.phonettesttask.repository.MessageRepository;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.hibernate.Session;
import javax.inject.Singleton;
import javax.ws.rs.ApplicationPath;
@ApplicationPath("/rest/*")
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
packages("org.alexdzot.phonettesttask");
register(new AbstractBinder() {
@Override
protected void configure() {
bindFactory(SFFactory.class).to(Session.class);
bindFactory(MessageRepositoryFactory.class).to(MessageRepository.class).in(Singleton.class);
}
});
}
}
DefaultMessageRepository
import org.alexdzot.phonettesttask.model.Message;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.jvnet.hk2.annotations.Service;
import javax.inject.Inject;
import java.util.List;
@Service
public class DefaultMessageRepository implements MessageRepository {
@Inject
private Session session;
public void saveMessage(Message message) {
Session session = null;
Transaction tx = null;
try {
tx = session.beginTransaction();
session.save(message);
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
session.close();
}
}
public List<Message> getAllMessages() {
Session session = null;
Transaction tx = null;
List<Message> messages = null;
try {
tx = session.beginTransaction();
messages = session.createCriteria(Message.class).list();
} catch (Exception e) {
tx.rollback();
} finally {
session.close();
return messages;
}
}
}
但是当我运行应用程序并尝试调用存储库方法时,我得到了NullPoinerException。我无法理解我做错了什么。 这就是Tomcat日志所说的:
*08-Aug-2015 02:42:18.232 SEVERE [http-nio-8080-exec-10] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [org.alexdzot.phonettesttask.config.ApplicationConfig] in context with path [] threw exception [java.lang.NullPointerException] with root cause
java.lang.NullPointerException
at org.alexdzot.phonettesttask.repository.DefaultMessageRepository.getAllMessages(DefaultMessageRepository.java:42)
at org.alexdzot.phonettesttask.service.MessageResource.viewSentMessages(MessageResource.java:38)
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:497)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:205)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:308)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:291)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1140)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:403)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:386)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:334)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:221)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:617)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478)
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)*
任何想法我的解决方案有什么问题以及导致该问题的原因是什么?
答案 0 :(得分:5)
主要问题:
[java.lang.NullPointerException]
查看您的存储库类
@Service
public class DefaultMessageRepository implements MessageRepository {
@Inject
private Session session; <-------------------+
| // You shadow session
public void saveMessage(Message message) { |
Session session = null; <--------------+
Transaction tx = null;
try {
tx = session.beginTransaction();
...
}
...
}
您正在注入注入的字段session
。所以你只是使用本地session
,它是null。所以在你的方法中,只需摆脱Session session = null;
。注入应该可以正常工作,您应该只能使用session
字段。
另一个问题:
所有请求都使用相同的Session
。由于DefaultMessagFactory
是单身,HK2声称Session
也应该是单身,因为它包含在单身中。因此,不是将SFFactory
作为默认@PerLookup
范围,而是获得一个单例工厂,因此只会创建一个Session
。这不是您应该要的行为。您可以通过在工厂类中放置一些打印语句来测试它。
确保为每个请求创建新Session
的一种方法是:
使用javax.inject.Provider<Session>
,懒洋洋地加载会话,这将允许使用它来保持我们配置的范围。
@Inject
private javax.inject.Provider<Session> session;
@Override
public void saveEvent(Event event) {
Session s = session.get();
Transaction tx = s.beginTransaction();
在请求范围中配置SFFactory
@Override
protected void configure() {
bindFactory(SFFactory.class)
.to(Session.class)
.in(RequestScoped.class);
}
要解决的另一件事是SessionFactory
应该是应用程序中的单个实例。为此,我们可以为它创建一个工厂,并将其注入SFFactory
。例如
public class SessionFactoryFactory implements Factory<SessionFactory> {
private final SessionFactory factory;
public SessionFactoryFactory() {
Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
StandardServiceRegistryBuilder srBuilder = new StandardServiceRegistryBuilder();
srBuilder.applySettings(configuration.getProperties());
factory = configuration.buildSessionFactory(srBuilder.build());
System.out.println("--- SessionFactory Created ---");
}
@Override
public SessionFactory provide() {
System.out.println("--- SessionFactory Provided ---");
return factory;
}
@Override
public void dispose(SessionFactory factory) {
factory.close();
}
}
在SFFactory
public class SFFactory implements Factory<Session> {
private final SessionFactory factory;
@Inject
public SFFactory(SessionFactory factory) {
this.factory = factory;
}
@Override
public Session provide() {
System.out.println("--- Session Created ---");
return factory.openSession();
}
@Override
public void dispose(Session session) {
if (session.isOpen()) {
session.close();
}
}
}
您的配置会更改为
@Override
protected void configure() {
bindFactory(SessionFactoryFactory.class)
.to(SessionFactory.class)
.in(Singleton.class);
bindFactory(SFFactory.class)
.to(Session.class)
.in(RequestScoped.class);
}
所以除了阴影之外,另一个主要问题是OP没有显示的MessageRepositoryFactory
(在评论的github项目中)。
public class MessageRepositoryFactory implements Factory<MessageRepository> {
@Override
public MessageRepository provider() {
return new DefaultMessageRepository();
}
...
}
当您实例化自己的对象时,默认情况下,框架不会处理注入。这就是为什么注射Session
没有发生的原因。
您可以像这样绑定
,而不是像这样使用Factory
bind(DefaultMessageRepository.class).to(MessageRepository.class).in(..);
这样框架就会创建实例。 Factory
实际上只应该在无法绑定上述方式的地方使用,例如你有一些初始化要做。我们甚至可能没有为Factory
创建SessionFactoryFactory
,而是在其他地方完成了所有会话工厂配置,只是绑定了实例。例如
SessionFactory sessionFactory =...
...
bind(sessionFactory).to(SessionFactory.class);
我们只绑定一个SessionFactory
单例。