【问题标题】:Injectind Implementation automatically on runtime over CDI通过 CDI 在运行时自动注入实现
【发布时间】:2017-07-17 23:32:18
【问题描述】:

我正在尝试找出适合我需要的 CDI 和最佳方法。 我有一个与普通 tcp 通信交互的服务(TcpServiceImpl)。现在这个服务有一些地方需要通知某人发生了什么事。对于这些信息,我有接口TcpConnection,需要将 CDI 注入到正确的实现中。另一个问题是服务TcpServiceImpl本身被注入到一个定期执行的作业(TcpConnectionJob)中,并调用该服务来做事。 这意味着服务TcpServiceImpl 将多次存在。每个都有它处理的另一个 tcp 连接,并且有另一个设备需要另一个驱动程序/协议注入接口TcpConnection

让我展示参与此场景的三个元素:

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

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;
}

这里还有一个示例 sn-p,说明何时在我现有的服务中调用它:

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?

问题:

但我仍然不确定使用哪种方式/方法以及正确的方法是什么。任何帮助将不胜感激。

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

【问题讨论】:

    标签: java ejb javabeans cdi


    【解决方案1】:

    所以这是我想出的解决方案。现在唯一的问题是让回调工作,但这是不同的。这是对我有用的解决方案:

    /**
     * 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
    

    【讨论】:

      【解决方案2】:

      【讨论】:

      • 很遗憾我不能使用 CDI 事件。我本来想这样做,但由于预计会有大量的流量和数据通过应用程序,所以我的建议被拒绝了。据我所知,事件是同步的,因此触发事件将导致程序等待所有观察者完成,直到执行进一步的代码。但是,如果我在通知其他人数据进来的过程中需要观察更多的数据怎么办?
      • @Nico:看看这篇有趣的文章,它解释了如何使 CDI 事件异步。它可以成为您的解决方案:piotrnowicki.com/2013/05/asynchronous-cdi-events
      • 感谢您的文章。真的很高兴知道,我会保存它,但我想考虑一个不使用 CDI 事件的解决方案。假设由于某人的拒绝,这是不可能的。我的想法是以某种方式创建一个生产者和一个限定符。这是一个有效的策略吗?
      • 我必须指出我不想也不能知道我的生产者中的每个实现。我需要某种查找来自动检测它...
      • 可悲的是,你正在和一个白痴一起工作。多次看到这个。在 Java EE 8 中,默认情况下会有异步事件。没什么好说的了。
      猜你喜欢
      • 2016-02-08
      • 2015-06-27
      • 2012-08-05
      • 1970-01-01
      • 1970-01-01
      • 2013-03-05
      • 2016-07-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多