Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring 使用新构造函数初始化自动连线bean时会发生什么?_Spring_Spring Mvc_Autowired - Fatal编程技术网

Spring 使用新构造函数初始化自动连线bean时会发生什么?

Spring 使用新构造函数初始化自动连线bean时会发生什么?,spring,spring-mvc,autowired,Spring,Spring Mvc,Autowired,我过去用过弹簧。我搬到了另一个团队,在那里我开始熟悉代码库。我找到了下面的代码,并试图理解它是如何工作的,以及spring是如何在这种情况下注入自连线对象的。从我对Spring的基本知识来看,这绝对不是正确的方法。但令人惊讶的是,这段代码已经在生产中很长时间了,并且没有发现任何问题 @Controller @RequestMapping("/start") public class AController implements Runnable, InitializingBean {

我过去用过弹簧。我搬到了另一个团队,在那里我开始熟悉代码库。我找到了下面的代码,并试图理解它是如何工作的,以及spring是如何在这种情况下注入自连线对象的。从我对Spring的基本知识来看,这绝对不是正确的方法。但令人惊讶的是,这段代码已经在生产中很长时间了,并且没有发现任何问题

@Controller
@RequestMapping("/start")
public class AController implements Runnable, InitializingBean {

    @Autowired
    private StartServiceImpl service = new StartServiceImpl(); // 1

    Thread thread;

    public void run() {

        service.start();
    }

    public void stop()  {
            try {
                thread.join(); 
            } catch (InterruptedException e) {
            }
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        thread = new Thread(this);
        thread.setPriority(Thread.MAX_PRIORITY);
        thread.start();
    }
}

@Component
public class StartServiceImpl {
    //methods
}
Q1)本地主机:8080/project/start应该做什么。没有定义GET或POST方法

问题2)在注释的第1行中,StartServiceImpl是自动连接的,并使用“new”构造。那么这里发生了什么。容器是注入bean还是只实例化一个对象

 @Controller
    @RequestMapping("/stop")

public class BController {

    @Autowired
    private StartServiceImpl service = new StartServiceImpl();

    @RequestMapping(value = "**", method = RequestMethod.GET)
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {

            service.shutdownRequested();
            new AController().stop(); // 2
        } catch (Exception e) {
        }
    }
}
Q3)同样在注释的第2行中,调用stop,在应用程序上下文中调用bean上的stop,或者创建一个新对象并调用stop方法。在后一种情况下会发生什么?我们是否真的要停止已启动的服务?我想我们不会停止服务


我读过。这是非常有用的。但是它没有回答我的问题。

我将尝试具体回答这些问题,因为代码的目的很难理解(至少对我来说)

问题1)我不清楚该代码试图实现什么。正如您所注意到的,它不是一个控制器,我怀疑它以这种方式注册的唯一原因是它可以自动扫描(这也可以通过使用
@controller
来完成)。这只是一种预感,我不太理解它的用途

问题2)答案是将创建两个实例,一个通过
new
,另一个作为bean。在Spring中运行时,字段的最终值是bean,因为依赖项注入发生在构造之后。通常,当该类被设想在Spring之外使用时(例如,单元测试),就可以使用默认值初始化该字段

Q3)
stop()
将在新实例上调用,而不是在bean上调用。服务bean被停止是因为在该行上直接调用注入的bean,但我猜下一个将是NPE,因为通过
new
创建的目标对象上没有调用
AfterPropertieSet
。日志中没有显示NPE的唯一原因是下面的异常被吞没了。
线程
变量未初始化且保持为空


希望这能有所帮助,

此代码在许多方面都有缺陷

  • 自从Java5以来,手动启动线程就是一种反模式。这是混乱和太低的水平。应使用ExecutorServices
  • 可运行的Rest控制器?这是一种令人担忧的混杂现象
  • 服务是通过“新建”创建的,但随后会被自动连接的依赖项覆盖?WTF
  • 等等
  • 我会让线程一直运行,并使用控制器切换一个标志,决定线程是否真的做了一些事情,例如

    @Service
    class StartService{
       private boolean active;
       public void setActive(boolean active){this.active=active;}
    
    
       @Scheduled(fixedRate=5000)
       public void doStuff(){
          if(!active)return;
          // do actual stuff here
       }
    
    }
    
    现在rest控制器所做的就是切换“活动”字段的值。好处:

    • 每个班级只做一件事
    • 你总是知道你有多少线程

      • 您发布的代码非常奇怪

        Q1)localhost:8080/project/start应该做什么。那里 未定义GET或POST方法

        我认为
        localhost:8080/project/start
        将返回404错误(请求的资源不可用)。因为
        AController
        中没有映射的方法<代码>@RequestMapping类级别上的注释不足以向控制器发出请求。必须有一个映射方法

        但无论如何服务都会启动。因为
        AController
        实现了
        初始化bean
        。方法
        afterPropertieSet()
        将在创建控制器并初始化所有字段后由Spring调用

        问题2)在注释的第1行中,StartServiceImpl是自动连接的,并且 用“新”构建。那么这里发生了什么。这个容器有问题吗 注入bean或仅实例化一个对象

         @Controller
            @RequestMapping("/stop")
        
        public class BController {
        
            @Autowired
            private StartServiceImpl service = new StartServiceImpl();
        
            @RequestMapping(value = "**", method = RequestMethod.GET)
            public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                try {
        
                    service.shutdownRequested();
                    new AController().stop(); // 2
                } catch (Exception e) {
                }
            }
        }
        
        另一个奇怪的片段。在创建
        AController
        类的实例时,Java将创建
        StartServiceImpl
        的新实例。但在这之后,Spring将把它自己的实例(声明为组件)分配给这个字段。并且对第一个实例(由构造函数创建)的引用将丢失

        Q3)同样在注释的第2行中,调用停止,调用打开的停止 应用程序上下文或新对象中的bean被创建并 调用stop方法。在后一种情况下会发生什么?是 我们是否真的停止了已启动的服务?我想是的 不停止服务

        实际上,服务将停止。因为调用了
        service.shutdownRequested()。但是
        AController
        bean中的线程将继续工作<代码>新建AController().stop()将调用刚创建的实例的方法,但不会调用控制器的方法(由Spring创建的实例)



        这段代码完全错误地使用了Spring框架。

        使用
        新的AController().stop()
        有什么意义。我不明白。仅就测试而言,感谢SIS Q2最佳实践?一般来说,现场自动布线不被视为良好实践,而首选构造函数注入。唯一相对可接受的情况是在没有构造函数的测试类中。