Kafka源碼解讀——動態加載class類,減小項目依賴包

Java動態加載class類java

最多見的一種場景,某些功能服務項目里根本沒有使用到,可是由於項目裏引用了該依賴包的class類,因此你不得不在即便沒有使用到該服務的狀況下,仍讓要添加依賴到項目中。web

可是經過動態加載class類,可讓你的項目大大減小第三方包的依賴。緩存

核心思路就是經過反射和基本的判斷語句去控制對象的實例化。app

以Kafka源碼爲例:ide

如下是kafka中的壓縮模塊代碼函數

public Compressor(ByteBuffer buffer, CompressionType type) {
        this.type = type;
        this.initPos = buffer.position();
        
        ......

        appendStream = wrapForOutput(bufferStream, type, COMPRESSION_DEFAULT_BUFFER_SIZE); // kafka數據壓縮函數
    }
// the following two functions also need to be public since they are used in MemoryRecords.iteration
    static public DataOutputStream wrapForOutput(ByteBufferOutputStream buffer, CompressionType type, int bufferSize) {
        try {
            switch (type) {
                case NONE:
                    return new DataOutputStream(buffer);
                case GZIP: // 直接new
                    return new DataOutputStream(new GZIPOutputStream(buffer, bufferSize));
                case SNAPPY: // 經過反射(不使用SNAPPY時,減小依賴包)
                    try {
                        OutputStream stream = (OutputStream) snappyOutputStreamSupplier.get().newInstance(buffer, bufferSize);
                        return new DataOutputStream(stream);
                    } catch (Exception e) {
                        throw new KafkaException(e);
                    }
                case LZ4:
                    try {
                        OutputStream stream = (OutputStream) lz4OutputStreamSupplier.get().newInstance(buffer);
                        return new DataOutputStream(stream);
                    } catch (Exception e) {
                        throw new KafkaException(e);
                    }
                default:
                    throw new IllegalArgumentException("Unknown compression type: " + type);
            }
        } catch (IOException e) {
            throw new KafkaException(e);
        }
    }

你們會發現,使用GZIP時是直接new,而SNAPPY和LZ4是經過反射來實現的。this

源碼中對snappyOutputStreamSupplier的解釋:code

// dynamically load the snappy and lz4 classes to avoid runtime dependency if we are not using compression
    // caching constructors to avoid invoking of Class.forName method for each batch
    private static MemoizingConstructorSupplier snappyOutputStreamSupplier = new MemoizingConstructorSupplier(new ConstructorSupplier() {
        @Override
        public Constructor get() throws ClassNotFoundException, NoSuchMethodException {
            return Class.forName("org.xerial.snappy.SnappyOutputStream")
                .getConstructor(OutputStream.class, Integer.TYPE);
        }
    });
動態加載snappy和lz4類,以免在不使用壓縮/緩存構造函數的狀況下出現運行時依賴關係,從而避免爲每一個批調用class.forname方法

 

以報警業務來舉例,有A、B、C、D、E ,共5個客戶購買了你的項目,5個客戶都須要在你項目裏增長客戶本身定義的報警代碼,假設都是使用的webservice。對象

此時按照常規思路,你須要在你的項目裏引入5個客戶,也就是5個webservice的依賴包。get

可是一般某客戶只須要使用到本身定義的報警邏輯。以A舉例,A須要的只是A自身的報警邏輯,但你卻在提供的項目裏讓A強行引入B、C、D、E四個徹底不相關的依賴。

但經過反射,你只須要流程控制下走哪一條反射的邏輯,而後添加該條邏輯的依賴便可。

若是是更多的客戶以及更復雜的業務邏輯,經過反射進行動態加載,可讓你的項目依賴大大減小。

相關文章
相關標籤/搜索