java 春天:BeanCreationException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16724127/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 23:47:49  来源:igfitidea点击:

Spring: BeanCreationException

javaspringexceptionjavabeansautowired

提问by Mr. Polywhirl

I am trying to get the session from the session factory to use with my CRUD methods. I tried to set the session in the constructor, but the bean has not been initialized by then. How do I initialize it after the bean is created?

我正在尝试从会话工厂获取会话以与我的 CRUD 方法一起使用。我试图在构造函数中设置会话,但此时 bean 尚未初始化。创建 bean 后如何对其进行初始化?

Stacktrace

堆栈跟踪

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userDaoImpl' defined in file [/home/ryan/workspace/com-byteslounge-spring-tx/target/classes/com/byteslounge/spring/tx/dao/impl/UserDaoImpl.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.byteslounge.spring.tx.dao.impl.UserDaoImpl]: Constructor threw exception; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1011)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:957)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:490)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:607)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
    at com.byteslounge.spring.tx.Main.main(Main.java:19)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.byteslounge.spring.tx.dao.impl.UserDaoImpl]: Constructor threw exception; nested exception is java.lang.NullPointerException
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:163)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1004)
    ... 13 more
Caused by: java.lang.NullPointerException
    at com.byteslounge.spring.tx.dao.impl.UserDaoImpl.<init>(UserDaoImpl.java:24)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
    ... 15 more

UserDaoImpl.java

UserDaoImpl.java

package com.byteslounge.spring.tx.dao.impl;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.byteslounge.spring.tx.dao.UserDao;
import com.byteslounge.spring.tx.domain.User;

@Service
public class UserDaoImpl implements UserDao {

    @Autowired
    private SessionFactory sessionFactory;

    private Session session;

    public UserDaoImpl() {
        session = sessionFactory.getCurrentSession();
    }

    public SessionFactory getSessionFactory() {
        return this.sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void insertUser(User user) {
        session.save(user);
    }

    public void removeUserByName(String username) {
        User user = null;
        try {
            getUser(username);
        } catch (IndexOutOfBoundsException e) {
            System.out.println(username + " does not exist!");
        } finally {
            if (user != null)
                session.delete(user);
        }
    }

    public User getUserById(int userId) {
        return (User) session.get(User.class, userId);
    }

    public User getUser(String username) {
        // Query query = sessionFactory.getCurrentSession().createQuery("from User where username = :username");
        // query.setParameter("username", username);

        Query query = session.getNamedQuery(User.FIND_USER_BY_USERNAME).setString("username", username);
        return (User) query.list().get(0);
    }

    @SuppressWarnings("unchecked")
    public List<User> getUsers() {
        Criteria criteria = session.createCriteria(User.class);
        return criteria.list();
    }
}

applicationContext.xml

应用上下文.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="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.xsd">

    <tx:annotation-driven />

    <context:component-scan base-package="com.byteslounge.spring.tx.dao.impl" />
    <context:component-scan base-package="com.byteslounge.spring.tx.user.impl" />

    <bean
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location">
            <value>database.properties</value>
        </property>
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
        <property name="packagesToScan" value="com.byteslounge.spring.tx.domain" />
    </bean>

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager"
        p:sessionFactory-ref="sessionFactory">
    </bean>

</beans>

回答by Caesar Ralf

Use the @PostConstructtag and get the session then. Your beans will only be injected after your UserDaoImplis created and @PostConstructmethod will only be called by Spring after all your beans are injected.

使用@PostConstruct标签然后获取会话。您的 bean 只会在您UserDaoImpl创建之后被注入,并且@PostConstruct方法只会在您的所有 bean 被注入后被 Spring 调用。

@Service
public class UserDaoImpl implements UserDao {

    @Autowired
    private SessionFactory sessionFactory;

    private Session session;

    public UserDaoImpl() {
    }

    @PostConstruct
    public void init() {
        this.session = sessionFactory.getCurrentSession();
    }
    ...
}

Another way (better in my opnion) is inject by constructor and getting the current session only when you need it.

另一种方法(在我的选项中更好)是通过构造函数注入并仅在需要时获取当前会话。

    ...
    private final SessionFactory sessionFactory;

    @Autowired
    public UserDaoImpl(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    private Session currentSession() {
        return this.sessionFactory.getCurrentSession();
    }

EDIT:Use the second way preferably, because if you get the session only after construct, calls to your DAO won't work once that session is expired. Always use SessionFactory#getCurrentSession()when starting make calls at your transactional methods.

编辑:最好使用第二种方式,因为如果您仅在构造后获取会话,则一旦该会话过期,对 DAO 的调用将无法工作。SessionFactory#getCurrentSession()在您的事务方法开始进行调用时始终使用。

回答by Steve Oh

As Ralf points out, the constructor is executed too early and Spring did not inject anything at this point.

正如 Ralf 指出的那样,构造函数执行得太早,此时 Spring 没有注入任何内容。

Further, you may not hold a reference to Sessionas it relies on the SessionContext mechanism, which in turn may be thread bound or servlet request bound. Your bean may has a wider scope (e.g. singleton) and you will permanently store the session from the first caller or something!

此外,您可能不会持有对Session的引用,因为它依赖于 SessionContext 机制,而后者又可能是线程绑定或 servlet 请求绑定的。您的 bean 可能具有更广泛的范围(例如单例),您将永久存储来自第一个调用者或其他东西的会话!

I suggest to always get the session from sessionFactory when needed inside the bean.

我建议在 bean 内部需要时总是从 sessionFactory 获取会话。