有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

当接口作为参数提供时,java依赖项注入不起作用

这是我的控制器类

@Controller
public class HomeController{

    @RequestMapping("/")
    public String home(MyTest test){
        test.draw();
        return "homePage";
    }
}

在将MyTest(接口)作为参数传递给home方法时,Spring不会注入其实现类,而是抛出异常

SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/spring-mvc-demo] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: No primary or default constructor found for interface com.managers.MyTest] with root cause
java.lang.NoSuchMethodException: com.managers.MyTest.<init>()
    at java.lang.Class.getConstructor0(Unknown Source)
    at java.lang.Class.getDeclaredConstructor(Unknown Source)
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:209)
    at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:84)
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:132)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:124)
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:131)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:871)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:777)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:870)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:855)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1686)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

但是在直接传递实现类即MyTestImpl时,它工作得很好

@RequestMapping("/")
    public String home(MyTestImpl test){
        test.draw();
        return "homePage";
    }

如果出现接口,请在此说明异常原因。 下面是MyTest实现类

@Component
public class MyTestImpl implements MyTest{

    @Override
    public void draw() {
        System.out.println("inside test");

    }
}

春天。xml

<context:component-scan base-package="com.controllers,com.ManagerImpl" />
    <mvc:annotation-driven/>
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/" />
        <property name="suffix" value=".jsp" />
    </bean>

共 (4) 个答案

  1. # 1 楼答案

    是您的组件扫描值覆盖接口所在的包。使用@Autowired注释进行注射

  2. # 2 楼答案

    你所做的是正确的,只是你需要告诉Spring如何反序列化你的接口(也就是说,需要哪个具体的类实现)

        @JsonDeserialize(as=MyTestImpl.class)
        public interface MyTest  {
        ...
    

    另外,假设您正在使用Post方法,请将控制器更改为:

    @PostMapping(value = "/",
                consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
                produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        public String home(MyTest test){
            test.draw();
            return "homePage";
        }
    

    (“products”参数当然可以是text/html或您返回的任何内容)

  3. # 3 楼答案

    首先,我想指出,你们混合了不同的术语

    如前所述,自动布线是spring的核心概念。如前所述,@Autowire应该在setters上完成,对于非配置bean*,下面是相关的短语:

    Marks a constructor, field, setter method or config method as to be autowired by Spring's dependency injection facilities.

    其次,这里您试图将bean(@Component)注入到MVC控制器中,更具体地说,是注入bean的接口

    如果仔细查看文档(here),您会发现Spring支持各种参数,并且会尽可能地将它们传递给控制器方法

    这里的问题是,Spring无法知道将什么传递给您的方法。 当调用控制器时,spring将看到这个参数属于最后一类,即^{

    如果一个方法参数与上述任何一个参数都不匹配,默认情况下,如果它是由BeanUtils#isSimpleProperty确定的简单类型,它将被解析为@RequestParam,否则将被解析为@ModelAttribute

    因此,Spring会将其视为一个“模型属性”,但它无法知道如何映射它,因为接口不能被实例化,因此您的错误。p>

    现在,根据您的问题,您可以:

    作为@Controller的成员自动连接bean或接口,例如:

    @Controller
    public class HomeController{
    
        //might need @Qualifier if more than one implementation
        @Autowire
        private MyTest test; 
    
        @RequestMapping("/")
        public String home(){
            test.draw();
            return "homePage";
        }
    }
    

    或者将您的实现传递给您的方法控制器

    *Although i haven't found anything clear in the spring documentation that states what clearly is a config method, i'm pretty sure that does not apply to @Controller methods.

  4. # 4 楼答案

    你这样做是完全错误的。这是一个工作代码

    @Controller
    public class HomeController{
      private final MyTest test;
    
       @Autowired
       public HomeController(MyTest test) {
          this.test = test;
       }
    
       @RequestMapping("/")
       public String home(){
          test.draw();
          return "homePage";
       }
    }
    

    @RequestMapping注释的方法的参数应该/将以Pathvariable或RequestParams的形式出现,或者仅以HttpServletRequest对象本身的形式出现。这不是自动关联实例的方式

    依赖项注入在构造函数、字段和接口级别工作。不在方法参数级别。希望一切都清楚