【问题标题】:Consider defining a bean of type 'com.ensat.services.ProductService' in your configuration考虑在配置中定义“com.ensat.services.ProductService”类型的 bean
【发布时间】:2017-03-19 23:21:06
【问题描述】:

我有

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@ComponentScan(basePackages = {"hello","com.ensat.controllers"})
@EntityScan("com.ensat.entities")
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }

}

ProductController.java

package com.ensat.controllers;

import com.ensat.entities.Product;
import com.ensat.services.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Product controller.
 */
@Controller
public class ProductController {

    private ProductService productService;

    @Autowired
    public void setProductService(ProductService productService) {
        this.productService = productService;
    }

    /**
     * List all products.
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/products", method = RequestMethod.GET)
    public String list(Model model) {
        model.addAttribute("products", productService.listAllProducts());
        System.out.println("Returning rpoducts:");
        return "products";
    }

    /**
     * View a specific product by its id.
     *
     * @param id
     * @param model
     * @return
     */
    @RequestMapping("product/{id}")
    public String showProduct(@PathVariable Integer id, Model model) {
        model.addAttribute("product", productService.getProductById(id));
        return "productshow";
    }

    // Afficher le formulaire de modification du Product
    @RequestMapping("product/edit/{id}")
    public String edit(@PathVariable Integer id, Model model) {
        model.addAttribute("product", productService.getProductById(id));
        return "productform";
    }

    /**
     * New product.
     *
     * @param model
     * @return
     */
    @RequestMapping("product/new")
    public String newProduct(Model model) {
        model.addAttribute("product", new Product());
        return "productform";
    }

    /**
     * Save product to database.
     *
     * @param product
     * @return
     */
    @RequestMapping(value = "product", method = RequestMethod.POST)
    public String saveProduct(Product product) {
        productService.saveProduct(product);
        return "redirect:/product/" + product.getId();
    }

    /**
     * Delete product by its id.
     *
     * @param id
     * @return
     */
    @RequestMapping("product/delete/{id}")
    public String delete(@PathVariable Integer id) {
        productService.deleteProduct(id);
        return "redirect:/products";
    }

}

ProductService.java

package com.ensat.services;

import com.ensat.entities.Product;

public interface ProductService {

    Iterable<Product> listAllProducts();

    Product getProductById(Integer id);

    Product saveProduct(Product product);

    void deleteProduct(Integer id);

}

ProductServiceImpl.java

package com.ensat.services;

import com.ensat.entities.Product;
import com.ensat.repositories.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * Product service implement.
 */
@Service
public class ProductServiceImpl implements ProductService {

    private ProductRepository productRepository;

    @Autowired
    public void setProductRepository(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    @Override
    public Iterable<Product> listAllProducts() {
        return productRepository.findAll();
    }

    @Override
    public Product getProductById(Integer id) {
        return productRepository.findOne(id);
    }

    @Override
    public Product saveProduct(Product product) {
        return productRepository.save(product);
    }

    @Override
    public void deleteProduct(Integer id) {
        productRepository.delete(id);
    }

}

这是我的错误:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method setProductService in com.ensat.controllers.ProductController required a bean of type 'com.ensat.services.ProductService' that could not be found.


Action:

Consider defining a bean of type 'com.ensat.services.ProductService' in your configuration.

我有完整的日志:https://gist.github.com/donhuvy/b918e20eeeb7cbe3c4be4167d066f7fd

这是我的完整源代码 https://github.com/donhuvy/accounting/commit/319bf6bc47997ff996308c890eba81a6fa7f1a93

如何解决错误?

【问题讨论】:

  • 我在问题中添加了ProductServiceImpl,因为它是缺少的bean。

标签: java spring spring-mvc spring-boot


【解决方案1】:

该bean不是由Spring创建的,因为componentScan属性错过了ProductServiceImpl所在的包。

此外,@EnableJpaRepositories 不见了。因此,Spring 无法连接您的存储库。

@SpringBootApplication
@ComponentScan(basePackages = {"hello","com.ensat.controllers"})
@EntityScan("com.ensat.entities")

应替换为:

@SpringBootApplication
@ComponentScan(basePackages = {"hello","com.ensat.controllers", "com.ensat.services";
})
@EntityScan("com.ensat.entities")
@EnableJpaRepositories("com.ensat.repositories")

它会解决你的问题,但这种做法违背了 Spring 和 Spring Boot 的配置优势的约定。

如果Application bean 类位于一个父包中,所有其他 bean 类属于或属于它的子包,您将不再需要指定这两个注解:

@ComponentScan(basePackages = {"hello","com.ensat.controllers"})
@EntityScan("com.ensat.entities")

@SpringBootApplication 类中。

例如,将 Application 移动到 com.ensat 包中并将所有 bean 移动到此包或它的子包中都将解决您的配置问题并减轻您的配置。

package com.ensat;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application extends SpringBootServletInitializer {
    ...
}

为什么?

因为@SpringBootApplication 已经包含它们(以及更多):

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

但是使用当前类的包作为basePackage值来发现beans/entities/repositories等...

文档提到了这一点。

Here

许多 Spring Boot 开发人员总是对他们的主类进行注解 使用@Configuration、@EnableAutoConfiguration 和@ComponentScan。 由于这些注释经常一起使用(尤其是如果 你遵循上面的最佳实践),Spring Boot 提供了一个 方便的@SpringBootApplication 替代方案。

@SpringBootApplication 注解等价于使用 @Configuration、@EnableAutoConfiguration 和 @ComponentScan 及其 默认属性

这里讨论了@EnableAutoConfiguration77.3 Use Spring Data repositories point提供的实体发现:

Spring Boot 尝试猜测您的 @Repository 的位置 定义,基于它找到的 @EnableAutoConfiguration。 要获得 更多控制,使用 @EnableJpaRepositories 注释(来自 Spring 数据 JPA)。

【讨论】:

  • 您的错误是 由以下原因引起的:org.springframework.beans.factory.NoSuchBeanDefinitionException:没有为依赖项找到符合条件的 bean [com.ensat.repositories.ProductRepository]:预计至少有 1 个符合条件的 bean作为自动接线候选人。依赖注释:{}
  • 我更新了我的答案以处理丢失的存储库。试试:)
【解决方案2】:

我遇到了这个错误,我花了整整一个下午才弄明白。我检查了每个 stackoverflow 帖子、spring.io 文档、与此问题相关的 github 问题,但没有一个答案可以解决问题。

总之,我试过了:

  1. 重组和重命名我的包和类
  2. 为配置定义备用类
  3. 删除或重新创建错误的类
  4. 尽可能彻底地注释我的课程
  5. 完全定义类
  6. 为@Autowire 我的存储库创建多个代码实现
  7. 绝望地把我的头撞在墙上 -- 好吧,我可能有点过分了

鉴于我有两个存储库,@ComponentScan@EntityScan 注释都无法识别它们。所以总而言之,我无法对它们进行实例化或执行任何操作。

对我来说有什么诀窍,如果你已经用尽了尝试,我建议你做的是

  1. 仔细检查 pom.xml 中的项目依赖关系。该错误可能与您的代码无关(因为它不在我的代码上)。
  2. 如果您的依赖项正确,则创建一个新的 Maven 项目,使用您修改后的 pom.xml
  3. 更新您的 Maven 依赖项。值得一提的是,我是通过我的 IDE 完成的,即 Eclipse + Spring Tool Suite(我不相信 Spring Tool Suite 在更新方面有很大的不同) 4.构建你的包,让它们遵循最佳实践(有一篇关于这个here的好文章。)
  4. 然后,小心地将文件迁移回来。从 bean 开始,执行你的程序,检查错误;然后存储库,执行,测试;然后是任何启动脚本;然后是控制器等。慢慢来,确保一切正常。

有时调试这些应用程序会非常痛苦。我有我的份额。希望对你有帮助!

【讨论】:

    猜你喜欢
    • 2021-09-22
    • 1970-01-01
    • 2018-08-27
    • 2018-06-22
    • 1970-01-01
    • 2020-08-01
    • 2019-02-14
    • 2018-12-21
    • 2019-05-10
    相关资源
    最近更新 更多