2017-02-27 36 views
0

我想弄清楚CDI和适合我需求的最佳方法。 我有一个服务(TcpServiceImpl)与纯TCP通信交互。现在这项服务有一些地方需要通知某人某事发生了。对于这些信息,我有Interface TcpConnection,需要将CDI注入到正确的实现中。另一个问题是服务TcpServiceImpl本身被注入一个定期执行并调用服务来执行任务的作业(TcpConnectionJob)中。 这意味着服务TcpServiceImpl将存在多次。每一个都有另外一个tcp连接,并且有另一个设备需要在Interface TcpConnection中注入另一个驱动/协议。通过CDI在运行时自动执行Injectind实现

让我教的三个要素参与这样的场景:

这里是会得到多个实现的接口:

public interface TcpConnection 
{ 

    /** 
    * Connected. 
    * 
    * @throws NGException the NG exception 
    */ 
    public void connected() throws NGException; 

    /** 
    * This method will send the received data from the InputStream of the connection. 
    * 
    * @param data the received data 
    * @throws NGException the NG exception 
    */ 
    public void received(byte[] data) throws NGException; 

    /** 
    * Usable for the protocol to send data to the device. 
    * 
    * @param data the data to send to the device (Will be converted to byte[] with getBytes()) 
    * @throws NGException the NG exception 
    */ 
    public void send(String data) throws NGException; 

    /** 
    * Usable for the protocol to send data to the device. 
    * 
    * @param data the data to send to the device (Will be send as is) 
    * @throws NGException the NG exception 
    */ 
    public void send(byte[] data) throws NGException; 

    /** 
    * This method will inform the protocol that the connection got closed. 
    * 
    * @throws NGException the NG exception 
    */ 
    public void closed() throws NGException; 
} 

另外这里的时候,这将在被称为一个例子片断我现有的服务:

public class TCPServiceImpl implements TCPService, Runnable 
{ 
/** The callback. */ 
private TcpConnection callback; 
private void disconnect() 
{ 
    connection.disconnect(); 
    if (!getStatus(jndiName).equals(ConnectionStatus.FAILURE)) 
    { 
    setStatus(ConnectionStatus.CLOSED); 
    } 
    /* TODO: Tell driver connection is closed! */ 
    callback.closed(); 
} 
} 

下面是调用服务的类,然后需要动态注入正确的实现界面。

public class TcpConnectionJob implements JobRunnable 
{ 
    /** The service. */ 
    private TCPService service; 

    public void execute() 
    { 
    service.checkConnection(connection); 
    } 
} 

服务注入callback必须被链接到正确的“协议”或“驱动器”,将翻译的数据或处理逻辑的设备的实现。将有多个驱动程序实现的接口行为不同,我需要注入正确的。该决定的限定词可以是设备的名称。现在,我看了看下面的链接:

Understanding the necessity of type Safety in CDI

How to programmatically lookup and inject a CDI managed bean where the qualifier contains the name of a class

How to use CDI qualifiers with multiple class implementations?

问:

但是,我还是不确定哪种方式/方法来使用,是什么正确的方式。任何帮助,将不胜感激。

我的第一个想法是关于将我的界面复制到Qualifier Interface并添加这个输入限定符的可能性。这是一个好主意吗?

回答

0

所以这是我的解决方案,我想出了。现在唯一的问题是要回调工作,但这是不同的。继承人为我工作的解决方案:

/** 
* The Qualifier interface TcpDriver. The value of this annotation is the name the implementation 
* is found under. Please only enter values that are configured in the wildfly config as the name of 
* the device. 
*/ 
@Documented 
@Qualifier 
@Retention(RUNTIME) 
@Target({ TYPE, FIELD, METHOD, PARAMETER }) 
public @interface TcpDriver 
{ 

    /** 
    * Value. 
    * 
    * @return the string 
    */ 
    String value(); 
} 

只是限定符接口的默认实现:

/** 
* The Class TcpDriverImpl. 
*/ 
public class TcpDriverImpl extends AnnotationLiteral<TcpDriver> implements TcpDriver 
{ 

    /** The Constant serialVersionUID. */ 
    private static final long serialVersionUID = 1L; 

    /** The name. */ 
    private final String name; 

    /** 
    * Instantiates a new tcp driver impl. 
    * 
    * @param name the name 
    */ 
    public TcpDriverImpl(final String name) 
    { 
    this.name = name; 
    } 

    /** {@inheritDoc} */ 
    @Override 
    public String value() 
    { 
    return name; 
    } 

} 

现在测试执行,测试它:

@TcpDriver("terminal1") 
@Dependent 
public class TestDriverImpl implements TcpConnection 
{ 

    /** The log. */ 
    private Log log; 

    @Inject 
    public void init(Log log) 
    { 
    this.log = log; 
    } 

    @Override 
    public void connected() throws NGException 
    { 
    // TODO Auto-generated method stub 
    log.info("IT WORKS!!"); 
    } 

    @Override 
    public void received(byte[] data) throws NGException 
    { 
    // TODO Auto-generated method stub 

    } 

    @Override 
    public void send(String data) throws NGException 
    { 
    // TODO Auto-generated method stub 

    } 

    @Override 
    public void send(byte[] data) throws NGException 
    { 
    // TODO Auto-generated method stub 

    } 

    @Override 
    public void closed() throws NGException 
    { 
    // TODO Auto-generated method stub 
    log.info("BYE BYE"); 
    } 

}

最后但并非最不重要的一点是,我在我的服务中注入了所有这些:

/** The callback Instance for the driver to find. */ 
    @Inject 
    @Any 
    private Instance<TcpConnection> callback; 

    private TcpConnection driver; 
    /** 
    * Inject driver. 
    */ 
    private void injectDriver() 
    { 
    final TcpDriver driver = new TcpDriverImpl(name); 
    this.driver = callback.select(driver).get(); 
    } 

我希望这可以帮助我的人有同样的要求。

PS:有点日志显示,如果你检查日志输出在测试执行,然后查看日志:)

2017-02-28 08:37:00,011 INFO starting TCPConnection: TcpDevice1 with status: NOT_CONNECTED 
2017-02-28 08:37:00,018 INFO initializing terminal1 
2017-02-28 08:37:00,019 INFO Creating socket for: terminal1 with port: XXXXX 
2017-02-28 08:37:00,023 INFO Updated Status to CONNECTED for connection TcpDevice1 
2017-02-28 08:37:00,024 INFO opened connection to terminal1 
2017-02-28 08:37:00,026 INFO (terminal1) IT WORKS!! 
2017-02-28 08:37:00,038 INFO (terminal1) terminal1: In threaded method run 
2017-02-28 08:37:00,039 INFO (terminal1) waiting for data... 
2017-02-28 08:39:00,045 INFO (terminal1) Socket closed! 
2017-02-28 08:39:00,045 INFO (terminal1) BYE BYE 
1
+0

可悲的是我不能使用CDI事件它的工作原理。我本来想这样做,但由于预计会有大量的流量和数据通过应用程序,我的建议就被拒绝了。 据我所知,事件是同步的,所以触发一个事件将导致程序等待所有的观察者被完成,直到进一步的代码被执行。但是如果我在通知其他人数据进来时需要注意更多传入数据呢? – Nico

+0

@Nico:看看这篇有趣的文章,它解释了如何制作CDI事件异步。它可以成为您的解决方案:http://piotrnowicki.com/2013/05/asynchronous-cdi-events/ – Rouliboy

+0

感谢您的文章。真的很高兴知道,我会保存它,但我想在不使用CDI事件的情况下考虑解决方案。让我们说这是不可能的,因为拒绝某人。我的想法是关于创建一个制片人与某个限定词相结合的方式。这是一个有效的策略吗? – Nico