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四個徹底不相關的依賴。
但經過反射,你只須要流程控制下走哪一條反射的邏輯,而後添加該條邏輯的依賴便可。
若是是更多的客戶以及更復雜的業務邏輯,經過反射進行動態加載,可讓你的項目依賴大大減小。