使用新构造函数初始化autowired bean时会发生什么?

时间:2016-06-09 05:22:59

标签: spring spring-mvc autowired

我过去曾使用过Spring。我搬到了另一个团队,在那里我熟悉了代码库。我找到了以下代码,并试图了解它是如何工作的以及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)预期localhost:8080/project/start会做什么。没有定义GET或POST方法。

Q2)在注释行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方法。在后一种情况下会发生什么?我们真的停止了已启动的服务吗?我想我们并没有停止这项服务。

我看过this post。这非常有用。但它没有回答我的问题。

3 个答案:

答案 0 :(得分:2)

此代码在许多层面都存在缺陷。

  1. 从Java 5开始,手动启动线程就是反模式。它太乱了,太低级了。应该使用ExecutorServices。
  2. 作为Runnable的Rest控制器?这是一个令人担忧的混乱问题。
  3. 服务是通过new创建的,然后用自动连接的依赖项覆盖? WTF!
  4. 我一直保持线程运行scheduling the task with the @Scheduled annotation并使用控制器来切换一个标志,该标志决定线程是否实际执行某些操作,例如。

    ( /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/) 
    

    现在所有其他控制器都会切换&#34;活动&#34;的值。领域。优点:

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

答案 1 :(得分:1)

我会特意回答这些问题,因为代码的目的很难理解(至少对我来说)。

Q1)我不清楚这段代码试图实现的目标。正如你所注意到的那样,它不是一个控制器,我怀疑它以这种方式注册的唯一原因是它被自动扫描(这也可以通过使用@Controller来完成。这只是一个预感,我不太了解它的目的。

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

Q3)stop()将在新实例上调用,而不是bean。服务bean因为在注入bean的那一行上面的直接调用而停止了,但是我想,下一个将是NPE,因为afterPropertiesSet没有在通过new创建的目标对象上调用。这不能在日志中显示NPE的唯一原因是因为下面的例外被吞下。 thread变量未初始化并保持为NULL。

希望这有帮助,

答案 2 :(得分:1)

您发布的代码非常奇怪。

  

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

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

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

  

Q2)在注释行1上,StartServiceImpl是自动装配的   用&#34; new&#34;构建。那么这里发生了什么。做容器   注入bean或只是一个对象被实例化。

另一个奇怪的片段。 Java将在创建StartServiceImpl类的实例时创建AController的新实例。但在那之后,Spring会将它自己的实例(声明为组件)分配给该字段。并且对firs实例的引用(由构造函数创建)将丢失。

  

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

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

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