简体   繁体   中英

Why am I getting a NoSuchBeanDefinitionException when I have already defined the bean?

I just want to start off by saying that I am new to Spring, JPA, and hibernate. So I am trying my best. Also, I am using Java based configuration, so no xml used here.

So, I am trying to run an integration test on my PersonDAOJpa class. While I am running the integration test, I am getting an error for NoSuchBeanDefinitionException for the bean "jpaDao". I have already defined the bean in my DatabaseConfig class. So why I am getting this error even though I have defined it?

Here is the code and error trace that should be relevant to this question:

Error Trace:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'jpaDao' is defined
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1168)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:281)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:962)
    at com.orgchart.PersonServiceJPAIntegrationTest.<init>(PersonServiceJPAIntegrationTest.java:34)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:217)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:199)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:259)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:261)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:219)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

DatabaseConfig:

@Configuration
@PropertySource("classpath:application.properties")
@EnableTransactionManagement
public class DatabaseConfig{



    @Bean(name="jpaDao")
    public PersonDAOJpa jpadao(){

        return new PersonDAOJpa();

    }

    @Bean(name="jdbcDao")
    public PersonDAOJdbc dao(){

        return new PersonDAOJdbc();

    }


    @Bean
    public JdbcTemplate jdbc(DataSource ds){

        JdbcTemplate jdbc= new JdbcTemplate(dataSource());

        return jdbc;
    }


   @Bean
   public PersonService ps(){

       PersonService ps= new PersonServiceImpl();

       return ps;
   }


   @Bean(name="ds")
    public DataSource dataSource() {

        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/------");
        ds.setUsername(" ");
        ds.setPassword(" ");

        return ds;

    }


   @Bean
   public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {

       LocalContainerEntityManagerFactoryBean em =
           new LocalContainerEntityManagerFactoryBean();
       em.setDataSource(dataSource());
       em.setPackagesToScan(new String[] {"com.orgchart"});
       JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
       em.setJpaVendorAdapter(vendorAdapter);
       em.setJpaProperties(additionalProperties());
       return em;
   }


   @Bean
   public PlatformTransactionManager transactionManager() {

       JpaTransactionManager transactionManager = new JpaTransactionManager();
       transactionManager.setEntityManagerFactory(entityManagerFactoryBean()
           .getObject());
       return transactionManager;
   }


   @Bean
   public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {

       return new PersistenceExceptionTranslationPostProcessor();
   }


   Properties additionalProperties() {

       return new Properties() {

           private static final long serialVersionUID = 1L;

           { // Hibernate Specific:
               setProperty("hibernate.hbm2ddl.auto", "update");
               setProperty("hibernate.dialect",
                   "org.hibernate.dialect.MySQL5Dialect");
           }
       };

   }



}

IntegrationTest:

@ContextConfiguration(classes = {IntegrationTestConfig.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class PersonServiceJPAIntegrationTest {



    ApplicationContext context= new AnnotationConfigApplicationContext(DatabaseConfig.class);

    PersonDAO personDao = context.getBean("jpaDao", PersonDAO.class);

    PersonServiceImpl ps = new PersonServiceImpl(personDao);


    @Before
    public void setUp() throws Exception {


    }



    @After
    public void tearDown() throws Exception {

    }

......


}

PersonDAOJpa:

@Component("jpaDao")
public class PersonDAOJpa implements PersonDAO{



        @PersistenceContext
        private EntityManager em;



        public PersonDAOJpa(){

        }


        public EntityManager getEm() {

            return em;
        }


        public void setEm(EntityManager em) {

            this.em = em;
        }

    .....

}

**UPDATE:

IntegrationTestConfig:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;



@Configuration
@ComponentScan
public class IntegrationTestConfig {


}

Also, there is a Service layer in my application, I just didn't add it below because I don't want to add irrelevant information. But if you do need it or you need more code or information, I will add it.

The problem is with your @ComponentScan annotation. Since you have not defined basepackages (packages to scan) by default it uses the current package of your test as target package.

Change it to:

@ComponentScan(basePackages = {"package.of.your.jpa.classes"})

to make it work.

Without your IntegrationTestConfig class this is a bit of a guess, but I'm going to guess that your test isn't actually pulling in your database configuration class.

In your IntegrationTest class, try changing

@ContextConfiguration(classes = {IntegrationTestConfig.class})

to

@ContextConfiguration(classes = {IntegrationTestConfig.class, DatabaseConfig.class})

By the by, you're doing redundant configuration, which can cause problems. For example, you're creating an instance of PersonDAOJpa using a @Bean annotation within a configuration class, but you've also marked PersonDAOJpa for component-scanning by annotating the class itself with @Component . Do one or the other, not both. My personal preference is to use configuration classes and @Bean annotations where the bean creation has extra steps. When the bean I want is just a simple instance created with the default constructor, I mark it for component-scanning, with @Component , for example .. then Spring creates the instance for me.

Lastly, in those cases where you are using a configuration class and the @Bean annotation, the bean instance will take on the name of the method. So if I were to create your PersonDAOJpa bean like this (instead of component-scanning):

@Bean
public PersonDAOJpa myPersonDao() {
  return new PersonDAOJpa();
}

then the bean would have the name "myPersonDao" within the Spring application context. Note that usually you don't have to worry about the name in any case, because Spring auto-wires by type, not by name, unless you tell it to do otherwise. Names only matter when you specifically have to have more than one bean of the same class, and then you would need to qualify them by name (I don't recommend this pattern, but sometimes it has to happen).

Change your Bean definition to return the interface PersonDAO

@Bean(name="jpaDao")
public PersonDAO jpadao(){

    return new PersonDAOJpa();

}

that way this line

PersonDAO personDao = context.getBean("jpaDao", PersonDAO.class);

will find the correct bean type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM