【问题标题】:Unsatisfied Dependency Exception in creating beans using Spring使用 Spring 创建 bean 时出现不满足的依赖异常
【发布时间】:2017-10-08 12:03:50
【问题描述】:

我正在尝试将 JPA 用于我的 spring 应用程序。我已将 JPATransactionManager 和 LocalEntityManagerFactoryBean 集成到 AppConfig 类中。现在,当我尝试调用 DaoImpl 中的一种方法时,AppConfig 无法自动装配这些类。这是我的代码

Test Class

public class Test {
public static void main(String[] args) {
      AnnotationConfigApplicationContext context = 
            new AnnotationConfigApplicationContext(AppConfig.class);

      BbDao personService = context.getBean(BbDao.class);
      personService.getDealByDealId("0194541605021NJMAPFU");
      context.close();
   }
}

应用配置

@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan(basePackages = "net.bb.spring")
public class AppConfig{

 @Bean
   public LocalEntityManagerFactoryBean getEntityManagerFactoryBean() {
      LocalEntityManagerFactoryBean factoryBean = new LocalEntityManagerFactoryBean();
      factoryBean.setPersistenceUnitName("MyPersistence");
      return factoryBean;
   }

   @Bean
   public JpaTransactionManager geJpaTransactionManager() {
      JpaTransactionManager transactionManager = new JpaTransactionManager();
      transactionManager.setEntityManagerFactory(getEntityManagerFactoryBean().getObject());
      return transactionManager;
   }

}

确认购买控制器

@RestController
public class ConfirmPurchaseController {

private Logger logger = Logger.getLogger(ConfirmPurchaseController.class);

@Autowired
private MyService myService;

@GetMapping("/purchase")
public ResultDto confirmpurchase(HttpServletResponse response) throws ClassNotFoundException, IOException {
    // Business Logic    
}
}

我的服务

@Component
public interface MyService {
    // Methods defined
}

MyServiceImpl

@Service
public class MyServiceImpl implements MyService, ServletContextAware {

private ServletContext servletContext;

public void setServletContext(ServletContext servletContext) {
    this.servletContext = servletContext;
}

public ServletContext getServletContext() {
    return servletContext;
}


// Added the implemented methods of the MyService Interface
} 

它抛出的异常是

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myServiceImpl': Unsatisfied dependency expressed through field 'servletContext'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.servlet.ServletContext' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

错误日志是

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'confirmPurchaseController': Unsatisfied dependency expressed through field 'myService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myServiceImpl': Unsatisfied dependency expressed through field 'servletContext'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.servlet.ServletContext' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)
at net.bb.spring.controller.Test.main(Test.java:14)

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myServiceImpl': Unsatisfied dependency expressed through field 'servletContext'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.servlet.ServletContext' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
... 14 more

 Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.servlet.ServletContext' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
... 27 more

任何想法都会对我很有帮助。

P.S : 我使用配置作为注释,没有 XML

【问题讨论】:

  • 你能分享一下我的服务类吗?
  • @MoatezBouhdid,更新为 myService 类
  • @JackFlamp,我在 MyServiceImpl 中添加了 ServletContext 和 setter 方法,并添加了实现 ServletContextAware,但错误仍然相同
  • 他的意思是实现MyServiceImpl。添加该类的代码

标签: java spring spring-mvc


【解决方案1】:

这不是答案,但是我还不能添加评论。

您是否尝试通过 setter 方法自动装配 ServletContext? - 从属性中删除 @Autowired - 删除您的上下文设置器之一(不必要的重复) - 将 setter 标记为 @Autowired

此外,从 MyService 中删除 @Component 注释,如果您在其实现中使用 @Service 注释,则没有必要。

【讨论】:

  • 我不推荐使用 field/setter 注入。这可能会在将来给您带来问题。最佳实践是使用构造函数注入。
  • @Staszko 现在该关注哪一个?
  • @Staszko,您可以在我的代码中看到我为 Impl 类使用了 ServletContext。我也试过你的方法。但还是同样的错误
  • 还是用public void setContext(ServletContext context) { this.context = context; } setter 试试吧,删除前一个并检查它是否有效。记住 MyService 中不必要的 @Component。如果设置器注入有效,它将为我们提供信息。
  • 我已经删除了 MyService 中的 @Component 并在我的 Impl 类中添加了带有 Autowired 注释的 setContext。但我收到此错误原因:org.springframework.beans.factory.NoSuchBeanDefinitionException:没有可用的“javax.servlet.ServletContext”类型的合格bean:预计至少有1个符合自动装配候选资格的bean。依赖注解:{@org.springframework.beans.factory.annotation.Autowired(required=true)}
【解决方案2】:

根据 Apache Tomcat 文档,ServletContext

定义一组 servlet 用来与其通信的方法 小服务程序容器。

每个 Java 虚拟机的每个“Web 应用程序”都有一个上下文。 (“Web 应用程序”是 servlet 和已安装内容的集合 在服务器 URL 命名空间的特定子集下,例如 /catalog 并且可能通过 .war 文件安装。)

这意味着 ServletContext 仅在像 Apache Tomcat 这样的 Servlet 容器中有效。但正如我所见,您试图通过在 main 方法中创建 bean 来运行普通的 Java 应用程序,这使得 ServletContext 的存在无效。

所以你要做的是:

第 1 步:构建您的 AppConfig 并覆盖所需的方法。

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"net.bb.spring"})
public class AppConfig extends WebMvcConfigurerAdapter {

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

        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/resources/**").addResourceLocations("/WEB-INF/");
        }
        //....
    }

第 2 步:创建 WebInitializer 以初始化 Dispatcher Servlet

public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] {AppConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }

}

第 3 步:创建服务层以自动装配 ServletContext

@Service
public class MyServiceImpl implements MyService {
    private ServletContext servletContext;

    @Autowire
    public MyServiceImpl(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    public ServletContext getServletContext() {
        return servletContext;
    }

    //...
}

第 4 步:将应用程序构建为 WAR 文件

第 5 步:将您的 WAR 文件部署到 Tomcat 的 webapp 文件夹(如果您使用的是 Tomcat)

第 6 步:启动 Tomcat

【讨论】:

    【解决方案3】:

    以下是您需要更改的内容:

    1) 接口不需要注解@Component,只需要在实现类上注解

    我的服务

    public interface MyService {
        // Methods defined
    }
    

    2) 使用构造函数注入获取ServeletContext的实例。

    @Service
    public class MyServiceImpl implements MyService, ServletContextAware {
        private ServletContext servletContext;
    
        @Autowire
        public MyServiceImpl(ServletContext servletContext) {
            this.servletContext = servletContext;
        }
    
    
    
        //TODO: other methods goes here...
    }
    

    注意ServletContext 不是Spring bean,因此除非你实现ServletContextAware,否则它不能被注入。保持你的实现类implementsServletContextAware

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-12
      • 2018-09-29
      • 2022-01-21
      • 2018-12-19
      • 2021-04-08
      • 2018-05-04
      • 2016-12-09
      • 2018-01-10
      相关资源
      最近更新 更多