【发布时间】:2017-05-04 01:51:53
【问题描述】:
我有一个使用 Hibernate 5.2 作为 orm 的 jax-rs/jersey rest 应用程序。还有一个使用令牌处理身份验证的弹簧过滤器。一切都很好,但有一个小问题。每个 dao 对象都在创建自己的会话工厂,就像这样。
public abstract class BaseDAO<T> {
protected SessionFactory sessionFactory = getSessionFactory();
protected final Validator validator = getValidator();
protected SessionFactory getSessionFactory() {
try {
return (SessionFactory) new Configuration().configure().buildSessionFactory();
} catch (Exception e) {
throw new IllegalStateException("Could not locate SessionFactory in JNDI");
}
}
protected Validator getValidator() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
return factory.getValidator();
}
@SuppressWarnings({"hiding", "unchecked"})
public <T> T save(final T o) {
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
T savedObj = (T) session.save(o);
tx.commit();
session.close();
return savedObj;
}
public void delete(final Object object) {
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
session.delete(object);
tx.commit();
session.close();
}
@SuppressWarnings("hiding")
public <T> T get(final Class<T> type, final int id) {
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
T obj = session.get(type, id);
tx.commit();
session.close();
return obj;
}
@SuppressWarnings({"hiding", "unchecked"})
public <T> T merge(final T o) {
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
T obj = (T) session.merge(o);
tx.commit();
session.close();
return obj;
}
@SuppressWarnings("hiding")
public <T> void saveOrUpdate(final T o) {
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
session.saveOrUpdate(o);
tx.commit();
session.close();
}
@SuppressWarnings({ "hiding", "deprecation", "unchecked" })
public <T> List<T> getAll(final Class<T> type) {
final Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
final Criteria crit = session.createCriteria(type);
List<T> results = crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
tx.commit();
session.close();
return results;
}
@SuppressWarnings({ "hiding", "deprecation", "unchecked" })
public <T> List<T> findByExample(final Class<T> type, T instance) {
try {
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
List<T> results = session
.createCriteria(type)
.add(Example.create(instance))
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
tx.commit();
session.close();
return results;
} catch (RuntimeException re) {
//log.error("find by example failed", re);
throw re;
}
}
这是一个问题,因为如果您创建多个 dao 对象,您很快就会用完连接,即使我在每次 dao 调用后调用 session.close() 也是如此。在对资源进行过多调用后,我的小型数据库实例抱怨连接过多。我的直接想法是会话工厂需要由 jersey 管理。所以我尝试了这样的工厂活页夹:
public class HibernateSessionFactory implements Factory<SessionFactory> {
protected SessionFactory sessionFactory;
@Override
public void dispose(SessionFactory arg0) {
sessionFactory.close();
}
@Override
public SessionFactory provide() {
try {
sessionFactory = (SessionFactory) new Configuration().configure().buildSessionFactory();
return sessionFactory;
} catch (Exception e) {
throw new IllegalStateException("Could not locate SessionFactory in JNDI");
}
}
}
在资源配置中:
register(new AbstractBinder() {
@Override
protected void configure() {
bindFactory(HibernateSessionFactory.class).to(SessionFactory.class);
}
});
并将 BaseDAO 更改为此
@Inject
protected SessionFactory sessionFactory
它似乎不起作用 - 会话工厂始终为空。另一个问题是弹簧过滤器不能使用球衣注入。过滤器是这样配置的。
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Order(2)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
private final com.renewedvoices.security.UserService userService;
private final TokenAuthenticationService tokenAuthenticationService;
private final SessionFactory sessionFactory;
public SpringSecurityConfig() {
super(true);
this.userService = new UserService();
this.tokenAuthenticationService = new TokenAuthenticationService("tooManySecrets", userService);
this.sessionFactory = createSessionFactory();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// Custom Token based authentication based on the header previously given to the client
http
.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService),
UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/rest/auth/**").permitAll()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().and()
.anonymous().and()
.servletApi().and()
.headers().cacheControl();
}
private SessionFactory createSessionFactory() {
try {
return (SessionFactory) new org.hibernate.cfg.Configuration().configure().buildSessionFactory();
} catch (Exception e) {
throw new IllegalStateException("Could not locate SessionFactory in JNDI");
}
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(new BCryptPasswordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
@Override
public UserService userDetailsService() {
return userService;
}
@Bean
public TokenAuthenticationService tokenAuthenticationService() {
return tokenAuthenticationService;
}
@Bean
public SerssionFactory sessionFactory() {
return sessionFactory;
}
}
无论我在 BaseDao 中使用@Autowired 还是@Inject,sessionFactory 始终为空。我不能切换到纯弹簧。有没有办法让这个 sessionFactory 工作?这是在休息服务中处理会话工厂的最佳方法,还是有更好的方法不针对每个请求打开新会话?我发现的几乎所有答案都是仅限弹簧的解决方案。任何帮助是极大的赞赏。
【问题讨论】:
-
您需要将 DAO 设置为 Spring bean,以便可以将其注入 Spring 组件中。然后对于 Jersey,您需要集成 Jersey 以使用 Spring 组件,以便您可以注入 Jersey。看看this post
-
我通读了答案并查看了链接的 git 项目。我不确定我是否遵循。你能帮忙指出我在上面做错了什么和他们在做什么之间的差距吗?我已经尝试标记@@Component 并配置如上所示的bean 定义。
-
我会发布一个答案,但这不是一个简单的设置。如果以后有时间,我会尝试为您整理一个示例项目。如果不是今天,也许明天的某个时间
标签: java spring hibernate rest jersey