• jxse2.6在jdk8下,JxtaMulticastSocket存在的问题


    JxtaMulticastSocket覆写了java.net.MulticastSocket的bind方法:
    @Override
        public void bind(SocketAddress addr) throws SocketException {
            if (isBound()) {
                throw new SocketException("Already bound");
            }
        }
     
    要求在JxtaMulticastSocket的构造函数中会调用bind方法,确保构造函数调用时socket没有被绑定,否则抛出SocketException异常
    然而JxtaMulticastSocket的基类java.net.MulticastSocket的构造函数在jdk7和jdk8中的处理是不同的
     
    jdk7:
        public MulticastSocket(SocketAddress bindaddr) throws IOException {
            super((SocketAddress) null);
    
            // Enable SO_REUSEADDR before binding
            setReuseAddress(true);
    
            if (bindaddr != null) {
                bind(bindaddr);
            }
        }

    jdk8:

        public MulticastSocket(SocketAddress bindaddr) throws IOException {
            super((SocketAddress) null);
    
            // Enable SO_REUSEADDR before binding
            setReuseAddress(true);
    
            if (bindaddr != null) {
                try {
                    bind(bindaddr);
                } finally {
                    if (!isBound())
                        close();
                }
            }
        }
    可见在jdk8中,如果未绑定,会额外调用close()方法,就是这个close()方法导致抛出了异常
    其实在这里不能调用close()方法,从代码上看JxtaMulticastSocket在实现的时候要求此时不能绑定(见其覆写的bind方法)
    而close方法也被JxtaMulticastSocket覆写了
    /**
         * Closes this MutlicastSocket.
         */
        @Override
        public synchronized void close() {
            if (closed) {
                return;
            }
            bound = false;
            closed = true;
            in.close();
            outputPipe.close();
            in = null;
        }

    此时in尚未初始化,故in.close()会导致java.lang.NullPointerException异常

    ————————————

    1 简单的话,可以修改JxtaMulticastSocket的构造函数,使其不再调用父类的构造函数以避免close()问题(父类构造函数中的相关代码要在子类中重新实现一遍)。
    2 或者不修改JxtaMulticastSocket的源码,我们干脆自己实现一个子类,提供自己的构造函数初始化代码。

    3 较好的方式那就要全面考虑JxtaMulticastSocket的实现了,那就比较复杂了

     ————————————————————————

    。。。

    1和2现在看起来不大现实,因为父类java.net.MulticastSocket最终都调用了如下构造方法:

        /**
         * Create a MulticastSocket bound to the specified socket address.
         * <p>
         * Or, if the address is {@code null}, create an unbound socket.
         *
         * <p>If there is a security manager,
         * its {@code checkListen} method is first called
         * with the SocketAddress port as its argument to ensure the operation is allowed.
         * This could result in a SecurityException.
         * <p>
         * When the socket is created the
         * {@link DatagramSocket#setReuseAddress(boolean)} method is
         * called to enable the SO_REUSEADDR socket option.
         *
         * @param bindaddr Socket address to bind to, or {@code null} for
         *                 an unbound socket.
         * @exception IOException if an I/O exception occurs
         * while creating the MulticastSocket
         * @exception  SecurityException  if a security manager exists and its
         *             {@code checkListen} method doesn't allow the operation.
         * @see SecurityManager#checkListen
         * @see java.net.DatagramSocket#setReuseAddress(boolean)
         *
         * @since 1.4
         */
        public MulticastSocket(SocketAddress bindaddr) throws IOException {
            super((SocketAddress) null);
    
            // Enable SO_REUSEADDR before binding
            setReuseAddress(true);
    
            if (bindaddr != null) {
                try {
                    bind(bindaddr);
                } finally {
                    if (!isBound())
                        close();
                }
            }
        }

    这意味着子类无论直接还是间接,最终都要调用到这个方法,故close()难以避免的啊!

    那就只有修改JxtaMulticastSocket覆写的close()方法了,原close()方法:

        /**
         * Closes this MutlicastSocket.
         */
        @Override
        public synchronized void close() {
            if (closed) {
                return;
            }
            bound = false;
            closed = true;
            in.close();
            outputPipe.close();
            in = null;
        }

    修改后:如果尚未绑定的话,close()不执行任何操作

        /**
         * Closes this MutlicastSocket.
         */
        @Override
        public synchronized void close() {
            // modified by cuizhf, 20131126
            // @see http://www.cnblogs.com/cuizhf/admin/EditPosts.aspx?postid=3443599
            if(!bound) {
                return;
            }
            if (closed) {
                return;
            }
            bound = false;
            closed = true;
            in.close();
            outputPipe.close();
            in = null;
        }

    或者这样写:

        /**
         * Closes this MutlicastSocket.
         */
        @Override
        public synchronized void close() {
            // modified by cuizhf, 20131126
            // @see http://www.cnblogs.com/cuizhf/admin/EditPosts.aspx?postid=3443599
            if (!bound || closed) {
                return;
            }
            bound = false;
            closed = true;
            in.close();
            outputPipe.close();
            in = null;
        }

    虽然不是很优雅,至少应该能解决眼前的问题。(实话说Jxse的代码确实算不上优雅)

     ————————————————————————————————————————————————————————

    另外一种修改方式就是将java.net.MulticastSocket单独从JDK中提出到在自己的工程中,然后按自己的需要修改(在构造函数中去掉close()的调用),最后使JxtaMulticastSocket继承自修改后的这个类。



     
     
     
     —————————————————————————————————————————————————————————
    好吧,从今天开始,secondegg项目的开发全面转向JDK8(JavaFX8)。
  • 相关阅读:
    Android 下拉刷新上啦加载SmartRefreshLayout + RecyclerView
    Maven 本地打war包
    数据库性能优化一
    SessionStateMode之Redis共享session
    SessionStateMode之SQL Server共享session
    iframe跨域
    Jenkins发布MVC应用程序
    Docker入门之一Docker在Window下安装
    Window下SVN服务器搭建以及客户端使用
    Window下Jenkins的安装
  • 原文地址:https://www.cnblogs.com/cuizhf/p/3443599.html
Copyright © 2020-2023  润新知