如何将第三方类自动组装到SpringBoot bean中?

时间:2019-03-01 01:49:51

标签: java spring-boot

在这种情况下,我已经看到了一些关于SO的问题,但这并不是我想要的。当您没有依赖项时,SpringBoot非常适合DI。但是,没有关于如何将第三方类注入到Spring托管bean中的示例。例如,请查看下面的代码:

@ServerEndpoint(value = "/resources")
class WebSocketController
{
    // This is contructed injected, but not shown here for brevity
    private ApplicationContext context; 
    private RequestFacade facade = context.getBean(RequestFacade.class);

    @OnMessage
    void handleMessage(Session session)
    {
        // Here session is a 3rd party library object
        facade.handleNewRequest(session)
    }
}

@Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
@Component
class CallSession 
{
    private Session session;

    CallSession(Session session)
    {
        this.session = session;
    }

    public void setSession(Session session)
    {
        // this should be called after construction of object when using Solution 2
        this.session = session;
    }

    public void start()
    {
        if (this.session == null)
            throw new IllegalStateException("Session is not set");
    }
}

@Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
@Component
class RequestFacade
{
    // This is contructed injected, but not shown here for brevity
    private ApplicationContext context; 

    public void handleNewRequest(Session session)
    {
        // Solution 1:
        // Require a new CallSession object for evey request
        // This won't compile since session is not managed by SpringBoot
        CallSession callSession = context.getBean(CallSession.class, session);
        callSession.start()

        // Solution 2:
        // Alternate would be to use this, but I am not a fan of this because the CallSession 
        // is in invalid state after construction. Because devs could forget to call callSession.setSession(session)
        CallSession callSession = context.getBean(CallSession.class);
        callSession.setSession(session);
        callSession.start();
    }
}

此处Session中传递的WebSocketController对象是第三方对象。 CallSession的功能需要此功能。因此,理想情况下,这应该在构造函数中传递。 CallSession是范围原型的SpringBoot管理对象。实例化CallSession时,除非Session由SpringBoot管理,否则我们不能将Session作为构造函数arg传递。

因此,替代解决方案(在RequestFacade.handleNewRequest()方法中标记为解决方案2)无需任何构造函数arg即可构造CallSession。然后确保通过调用CallSession.setSession()来设置会话。我认为这不是最好的设计,因为如果Session的运行需要CallSession,则应在构造过程中提供它,以防止CallSession处于无效状态。使用解决方案2时,我可以通过断言CallSession为空并抛出适当的异常来检查session是否处于非法状态。但是正如我之前提到的,这对我来说似乎不正确。

所以我有3个问题:  -当您的SpringBoot Beans之一在构造中需要第3方对象时,如何进行干净的设计?  -我的构造({解决方案2)CallSession是否没有args,并且在构造后立即通过了必要的args并在处理反模式之前检查对象状态?如果是,如何解决此问题?  -当您需要为新请求(CallSession实例化新的RequestFacade.handleNewRequest时,如何在不使用SCOPE_PROTOTYPE的情况下实例化范围类型为ApplicationContext的bean? (我读过,使用ApplicationContext是反模式DI)

编辑:与结束语中提到的不同,此问题与此不同。在该问题中,自动有线bean不接受构造函数arg(在我们的示例中为session)。关闭问题时请注意。请花点时间阅读和理解内容,然后再盲目地进行报告。

0 个答案:

没有答案