简体   繁体   中英

Configuring Spring beans

I want to make an AngularJS + Spring MVC + Hibernate + MySQL application. And I can't understand how to configure spring beans, so that I will be able to use @Autowired annotations to my repository and entity classes.

pom.xml dependencies:

<groupId>com.kspt</groupId>
<artifactId>pms</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>


<properties>
    <java-version>1.8</java-version>
    <spring-core.version>4.1.6.RELEASE</spring-core.version>
    <javax.servlet-api.version>3.1.0</javax.servlet-api.version>
    <spring-data-jpa.version>1.9.2.RELEASE</spring-data-jpa.version>
    <hibernate.version>5.2.12.Final</hibernate.version>
    <mysql-connector-java.version>5.1.34</mysql-connector-java.version>
    <commons-dbcp2.version>2.1.1</commons-dbcp2.version>
    <jta.version>1.1</jta.version>
    <junit.version>4.11</junit.version>
    <spring-webmvc.version>4.1.6.RELEASE</spring-webmvc.version>
    <spring-test.version>4.1.6.RELEASE</spring-test.version>
    <jstl.version>1.2</jstl.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring-core.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${spring-core.version}</version>
    </dependency>


    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
        <version>1.0.0.RELEASE</version>
    </dependency>


    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring-webmvc.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring-webmvc.version}</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>${javax.servlet-api.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>${spring-data-jpa.version}</version>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.2.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.2.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.2.3</version>
    </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${hibernate.version}</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql-connector-java.version}</version>
    </dependency>

    <!--JSF (include "jsf-api" and "jsf-impl")-->
    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.faces</artifactId>
        <version>2.2.10</version>
    </dependency>
</dependencies>

User entity class:

@Entity
@Table(name = "USERS")
public class User {

    @Id
    @Column(name = "ID")
    @GeneratedValue
    private Long id;

    @Column(name = "LOGIN", unique = true, nullable = false)
    private String login;

    @Column(name = "NAME")
    private String name;

    @JsonIgnore
    @Column(name = "PASSWORD")
    private String password;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

Repository for User :

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByLogin(String login);
}

Controller for User :

@RestController
@RequestMapping({"{login}"})
public class UserController {
    @Autowired
    UserRepository userRepository;

    @RequestMapping
    public User getUser(@PathVariable String login) {
        return userRepository.findByLogin(login)
                .orElseThrow(() -> new UserNotFoundException(login));
    }

    @RequestMapping(method = RequestMethod.POST)
    public void addUser(@PathVariable String login, @RequestBody User user) {
        userRepository.save(user);
    }
}

Configuration class:

@EnableWebMvc
@Configuration
@ComponentScan("com.kspt.pms")
public class AppConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/WEB-INF/resources/");
    }

    @Bean
    public ViewResolver getViewResolver(){
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/view/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

web.xml :

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>
                org.springframework.web.context.support.AnnotationConfigWebApplicationContext
            </param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                com.kspt.pms.AppConfig
            </param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.form</url-pattern>
    </servlet-mapping>

</web-app>

When I try to run application, I get following exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.kspt.pms.repository.UserRepository com.kspt.pms.controller.UserController.userRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.kspt.pms.repository.UserRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

As I understood, this happens because I have not created an applicationContext.xml file for Spring to know how to autowire all bean classes. I decided to try @EnableAutoConfiguration annotation, so that it will automaticly generate all required files. But when I add that annotation to AppConfig class, I get following error:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean]: Factory method 'entityManagerFactory' threw exception; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined

So I have several questions:

  1. Am I right that I need to create applicationContext.xml file with beans description, or when you use Hibernate (or Spring Data) it can somehow generate this file automatically somehow?

  2. Is there any other way no to write applicationContext manually, but to generate it somehow?

  3. If I'm wrong about applicationContext , then why I have these errors?

And maybe I'm just don't understand the concept of Spring and Hybernate properly. So can anyone help me please?

No qualifying bean of type [javax.sql.DataSource] is defined

That's the key of your problem. To support repositories and hibernate you need to declare DataSource bean with all the configs of your DB - URL, credentials etc.

See here for annotated DataSource config example or for XML based config here

You need something like this

@Bean
public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName(env.getRequiredProperty("jdbc.driverClassName"));
    dataSource.setUrl(env.getRequiredProperty("jdbc.url"));
    dataSource.setUsername(env.getRequiredProperty("jdbc.username"));
    dataSource.setPassword(env.getRequiredProperty("jdbc.password"));
    return dataSource;
}

What worked for me:

  1. I used IO Spring Platform for resolving dependencies and spring library versions in pom.xml :

     <groupId>com.kspt</groupId> <artifactId>pms</artifactId> <version>1.0-SNAPSHOT</version> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> <properties> <java-version>1.8</java-version> <spring-core.version>4.1.6.RELEASE</spring-core.version> <javax.servlet-api.version>3.1.0</javax.servlet-api.version> <spring-data-jpa.version>1.9.2.RELEASE</spring-data-jpa.version> <hibernate.version>5.2.12.Final</hibernate.version> <mysql-connector-java.version>5.1.34</mysql-connector-java.version> <commons-dbcp2.version>2.1.1</commons-dbcp2.version> <jta.version>1.1</jta.version> <junit.version>4.11</junit.version> <spring-webmvc.version>4.1.6.RELEASE</spring-webmvc.version> <spring-test.version>4.1.6.RELEASE</spring-test.version> <jstl.version>1.2</jstl.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>io.spring.platform</groupId> <artifactId>platform-bom</artifactId> <version>Brussels-SR6</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.5.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.5.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.5.2</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${javax.servlet-api.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-connector-java.version}</version> </dependency> <!--JSF (include "jsf-api" and "jsf-impl")--> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.faces</artifactId> <version>2.2.10</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.21</version> <!-- or use LATEST --> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.21</version> <!-- or use LATEST --> </dependency> </dependencies> 

  2. Added EntityManager, TransactionManager and DataSource beans to my config:

     @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setDriverClassName(env.getRequiredProperty("jdbc.driverClassName")); dataSource.setUrl(env.getRequiredProperty("jdbc.url")); dataSource.setUsername(env.getRequiredProperty("jdbc.username")); dataSource.setPassword(env.getRequiredProperty("jdbc.password")); return dataSource; } @Bean public JdbcTemplate jdbcTemplate(DataSource dataSource) { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); jdbcTemplate.setResultsMapCaseInsensitive(true); return jdbcTemplate; } @Bean public EntityManagerFactory entityManagerFactory() { HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setGenerateDdl(true); LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); factory.setJpaVendorAdapter(vendorAdapter); factory.setPackagesToScan("com.kspt.pms"); factory.setDataSource(dataSource()); factory.setPersistenceUnitName("my-pms"); factory.setPersistenceProviderClass(HibernatePersistenceProvider.class); factory.afterPropertiesSet(); return factory.getObject(); } @Bean public PlatformTransactionManager transactionManager() { JpaTransactionManager txManager = new JpaTransactionManager(); txManager.setEntityManagerFactory(entityManagerFactory()); return txManager; } 
  3. Added persistence.xml file to resources/META-INF and declared my persistance unit in it:

     <persistence-unit name="my-pms"> <class>com.kspt.pms.entity.BugReport</class> <class>com.kspt.pms.entity.Comment</class> <class>com.kspt.pms.entity.Message</class> <class>com.kspt.pms.entity.Milestone</class> <class>com.kspt.pms.entity.Project</class> <class>com.kspt.pms.entity.Ticket</class> <class>com.kspt.pms.entity.User</class> </persistence-unit> 

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