首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >当用新构造函数初始化自动配置bean时会发生什么?

当用新构造函数初始化自动配置bean时会发生什么?
EN

Stack Overflow用户
提问于 2016-06-09 05:22:58
回答 3查看 2.4K关注 0票数 1

我以前用过春天。我搬到了一个不同的团队,在那里我逐渐熟悉了代码基。我找到了下面的代码,并试图了解它是如何工作的,以及spring如何在这种情况下注入自动配置的对象。从我关于Spring的基本知识来看,这绝对不是正确的方法。但令人惊讶的是,这段代码已经制作了很长时间,没有发现任何问题。

代码语言:javascript
运行
复制
@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还是只是一个对象被实例化。

代码语言:javascript
运行
复制
 @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。它非常有用。但它没有回答我的问题。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-06-09 06:11:31

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

Q1)对我来说,这段代码试图实现什么还不清楚。正如您注意到的,它不是控制器,我怀疑它以这种方式注册的唯一原因是能够自动扫描(这也可以通过@Controller完成)。这只是一种预感,我不太明白它的目的。

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

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

希望这能帮上忙

票数 1
EN

Stack Overflow用户

发布于 2016-06-09 06:25:58

此代码在许多级别上都存在缺陷。

  1. 从Java 5开始,手动启动线程就是一种反模式。太乱了,太低了。应该使用ExecutorServices。
  2. 一个可运行的Rest控制器?这是一种令人毛骨悚然的担忧。
  3. 服务是通过新创建的,但随后被自动覆盖的依赖覆盖?见鬼!
  4. 等。

我会让线程一直运行, annotation,并使用控制器切换一个标志,以决定线程是否真的做了一些事情。

代码语言:javascript
运行
复制
@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控制器所做的就是切换"active“字段的值。好处:

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

Stack Overflow用户

发布于 2016-06-09 06:26:36

你发布的代码很奇怪。

Q1 )本地主机:8080/project/start预期会做什么。没有定义GET或POST方法。

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

但是服务还是会开始的。因为AController实现了InitializingBean。在创建控制器和初始化所有字段之后,Spring将调用afterPropertiesSet()方法。

( Q2)在注释的第1行上,StartServiceImpl是自动生成的,并且使用"new“构造。所以这里发生了什么。容器是注入bean还是只是一个对象被实例化。

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

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

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

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37717432

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档