【代理模式】補(bǔ)充筆記之CGLIB詳解

什么是CGLIB

CGLIB是一個(gè)強(qiáng)大的进胯、高性能的代碼生成庫(kù)送漠。其被廣泛應(yīng)用于AOP框架(Spring喧兄、dynaop)中逆皮,用以提供方法攔截操作宅粥。Hibernate作為一個(gè)比較受歡迎的ORM框架,同樣使用CGLIB來(lái)代理單端(多對(duì)一和一對(duì)一)關(guān)聯(lián)(延遲提取集合使用的另一種機(jī)制)电谣。CGLIB作為一個(gè)開(kāi)源項(xiàng)目秽梅,其代碼托管在github,地址為:https://github.com/cglib/cglib/releases/tag/RELEASE_3_2_10

小伙伴們可以直接進(jìn)入辰企,如下圖所示頁(yè)面风纠,然后點(diǎn)擊下載。

為什么使用CGLIB

CGLIB代理主要通過(guò)對(duì)字節(jié)碼的操作牢贸,為對(duì)象引入間接級(jí)別竹观,以控制對(duì)象的訪(fǎng)問(wèn)。我們知道Java中有一個(gè)動(dòng)態(tài)代理也是做這個(gè)事情的潜索,那我們?yōu)槭裁床恢苯邮褂肑ava動(dòng)態(tài)代理臭增,而要使用CGLIB呢?答案是CGLIB相比于JDK動(dòng)態(tài)代理更加強(qiáng)大竹习,JDK動(dòng)態(tài)代理雖然簡(jiǎn)單易用誊抛,但是其有一個(gè)致命缺陷是,只能對(duì)接口進(jìn)行代理整陌。如果要代理的類(lèi)為一個(gè)普通類(lèi)拗窃、沒(méi)有接口试和,那么Java動(dòng)態(tài)代理就沒(méi)法使用了瓮增。關(guān)于Java動(dòng)態(tài)代理阳堕,可以參者這里Java動(dòng)態(tài)代理分析

CGLIB組成結(jié)構(gòu)

CGLIB底層使用了ASM(一個(gè)短小精悍的字節(jié)碼操作框架)來(lái)操作字節(jié)碼生成新的類(lèi)潭枣。除了CGLIB庫(kù)外,腳本語(yǔ)言(如Groovy何BeanShell)也使用ASM生成字節(jié)碼宾毒。ASM使用類(lèi)似SAX的解析器來(lái)實(shí)現(xiàn)高性能驼修。我們不鼓勵(lì)直接使用ASM,因?yàn)樗枰獙?duì)Java字節(jié)碼的格式足夠的了解诈铛。關(guān)于ASM的下載乙各,我們這里也整理好了鏈接:https://asm.ow2.io/

訪(fǎng)問(wèn)此鏈接后,按照下圖所示操作幢竹,點(diǎn)頁(yè)面上的Maven Central耳峦,進(jìn)入下載頁(yè)面:

下載頁(yè)面,點(diǎn)擊下載按鈕進(jìn)行下載即可:

然后選擇第一個(gè)妨退,jar文件就好妇萄。

例子

說(shuō)了這么多,可能大家還是不知道CGLIB是干什么用的咬荷。下面我們將使用一個(gè)簡(jiǎn)單的例子來(lái)演示如何使用CGLIB對(duì)一個(gè)方法進(jìn)行攔截。

首先轻掩,我們需要在工程的POM文件中引入cglib的dependency幸乒,這里我們使用的是2.2.2版本

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2.2</version></dependency>

依賴(lài)包下載后,我們就可以干活了唇牧,按照國(guó)際慣例罕扎,寫(xiě)個(gè)hello world

publicclassSampleClass{publicvoidtest(){System.out.println("hello world");}publicstaticvoidmain(String[]args){Enhancer enhancer=newEnhancer();enhancer.setSuperclass(SampleClass.class);enhancer.setCallback(newMethodInterceptor(){@OverridepublicObjectintercept(Object obj,Method method,Object[]args,MethodProxy proxy)throwsThrowable{System.out.println("before method run...");Object result=proxy.invokeSuper(obj,args);System.out.println("after method run...");returnresult;}});SampleClass sample=(SampleClass)enhancer.create();sample.test();}}

在mian函數(shù)中,我們通過(guò)一個(gè)Enhancer和一個(gè)MethodInterceptor來(lái)實(shí)現(xiàn)對(duì)方法的攔截丐重,運(yùn)行程序后輸出為:

before method run...hello worldafter method run...

在上面的程序中腔召,我們引入了Enhancer和MethodInterceptor,可能有些讀者還不太了解扮惦。別急臀蛛,我們后面將會(huì)一一進(jìn)行介紹。就目前而言崖蜜,一個(gè)使用CGLIB的小demo就完成了

常用的API

目前網(wǎng)絡(luò)上對(duì)CGLIB的介紹資料比較少浊仆,造成對(duì)cglib的學(xué)習(xí)困難。這里我將對(duì)cglib中的常用類(lèi)進(jìn)行一個(gè)介紹豫领。為了避免解釋的不清楚抡柿,我將為每個(gè)類(lèi)都配有一個(gè)demo,用來(lái)做進(jìn)一步的說(shuō)明等恐。首先就從Enhancer開(kāi)始吧洲劣。

Enhancer

Enhancer可能是CGLIB中最常用的一個(gè)類(lèi)备蚓,和Java1.3動(dòng)態(tài)代理中引入的Proxy類(lèi)差不多(如果對(duì)Proxy不懂,可以參考這里)囱稽。和Proxy不同的是星著,Enhancer既能夠代理普通的class,也能夠代理接口粗悯。Enhancer創(chuàng)建一個(gè)被代理對(duì)象的子類(lèi)并且攔截所有的方法調(diào)用(包括從Object中繼承的toString和hashCode方法)虚循。Enhancer不能夠攔截final方法,例如Object.getClass()方法样傍,這是由于Java final方法語(yǔ)義決定的横缔。基于同樣的道理衫哥,Enhancer也不能對(duì)fianl類(lèi)進(jìn)行代理操作茎刚。這也是Hibernate為什么不能持久化final class的原因。

publicclassSampleClass{publicStringtest(String input){return"hello world";}}

下面我們將以這個(gè)類(lèi)作為主要的測(cè)試類(lèi)撤逢,來(lái)測(cè)試調(diào)用各種方法

@TestpublicvoidtestFixedValue(){Enhancer enhancer=newEnhancer();enhancer.setSuperclass(SampleClass.class);enhancer.setCallback(newFixedValue(){@OverridepublicObjectloadObject()throwsException{return"Hello cglib";}});SampleClass proxy=(SampleClass)enhancer.create();System.out.println(proxy.test(null));//攔截test膛锭,輸出Hello cglibSystem.out.println(proxy.toString());System.out.println(proxy.getClass());System.out.println(proxy.hashCode());}

程序的輸出為:

Hello cglibHello cglibclasscom.zeus.cglib.SampleClass$$EnhancerByCGLIB$$e3ea9b7java.lang.ClassCastException:java.lang.String cannot be cast to java.lang.Number? ? at com.zeus.cglib.SampleClass$$EnhancerByCGLIB$$e3ea9b7.hashCode(<generated>)...

上述代碼中,F(xiàn)ixedValue用來(lái)對(duì)所有攔截的方法返回相同的值蚊荣,從輸出我們可以看出來(lái)初狰,Enhancer對(duì)非final方法test()、toString()互例、hashCode()進(jìn)行了攔截奢入,沒(méi)有對(duì)getClass進(jìn)行攔截。由于hashCode()方法需要返回一個(gè)Number媳叨,但是我們返回的是一個(gè)String腥光,這解釋了上面的程序中為什么會(huì)拋出異常。

Enhancer.setSuperclass用來(lái)設(shè)置父類(lèi)型糊秆,從toString方法可以看出武福,使用CGLIB生成的類(lèi)為被代理類(lèi)的一個(gè)子類(lèi),形如:SampleClassEnhancerByCGLIBe3ea9b7

Enhancer.create(Object…)方法是用來(lái)創(chuàng)建增強(qiáng)對(duì)象的痘番,其提供了很多不同參數(shù)的方法用來(lái)匹配被增強(qiáng)類(lèi)的不同構(gòu)造方法捉片。(雖然類(lèi)的構(gòu)造放法只是Java字節(jié)碼層面的函數(shù),但是Enhancer卻不能對(duì)其進(jìn)行操作夫偶。Enhancer同樣不能操作static或者final類(lèi))界睁。我們也可以先使用Enhancer.createClass()來(lái)創(chuàng)建字節(jié)碼(.class),然后用字節(jié)碼動(dòng)態(tài)的生成增強(qiáng)后的對(duì)象兵拢。

可以使用一個(gè)InvocationHandler(如果對(duì)InvocationHandler不懂翻斟,可以參考這里)作為回調(diào),使用invoke方法來(lái)替換直接訪(fǎng)問(wèn)類(lèi)的方法说铃,但是你必須注意死循環(huán)访惜。因?yàn)閕nvoke中調(diào)用的任何原代理類(lèi)方法嘹履,均會(huì)重新代理到invoke方法中。

publicvoidtestInvocationHandler()throwsException{Enhancer enhancer=newEnhancer();enhancer.setSuperclass(SampleClass.class);enhancer.setCallback(newInvocationHandler(){@OverridepublicObjectinvoke(Object proxy,Method method,Object[]args)throwsThrowable{if(method.getDeclaringClass()!=Object.class&&method.getReturnType()==String.class){return"hello cglib";}else{thrownewRuntimeException("Do not know what to do");}}});SampleClass proxy=(SampleClass)enhancer.create();Assert.assertEquals("hello cglib",proxy.test(null));Assert.assertNotEquals("Hello cglib",proxy.toString());}

為了避免這種死循環(huán)债热,我們可以使用MethodInterceptor砾嫉,MethodInterceptor的例子在前面的hello world中已經(jīng)介紹過(guò)了,這里就不浪費(fèi)時(shí)間了窒篱。

有些時(shí)候我們可能只想對(duì)特定的方法進(jìn)行攔截焕刮,對(duì)其他的方法直接放行,不做任何操作墙杯,使用Enhancer處理這種需求同樣很簡(jiǎn)單,只需要一個(gè)CallbackFilter即可:

@TestpublicvoidtestCallbackFilter()throwsException{Enhancer enhancer=newEnhancer();CallbackHelper callbackHelper=newCallbackHelper(SampleClass.class,newClass[0]){@OverrideprotectedObjectgetCallback(Method method){if(method.getDeclaringClass()!=Object.class&&method.getReturnType()==String.class){returnnewFixedValue(){@OverridepublicObjectloadObject()throwsException{return"Hello cglib";}};}else{returnNoOp.INSTANCE;}}};enhancer.setSuperclass(SampleClass.class);enhancer.setCallbackFilter(callbackHelper);enhancer.setCallbacks(callbackHelper.getCallbacks());SampleClass proxy=(SampleClass)enhancer.create();Assert.assertEquals("Hello cglib",proxy.test(null));Assert.assertNotEquals("Hello cglib",proxy.toString());System.out.println(proxy.hashCode());}

ImmutableBean

通過(guò)名字就可以知道配并,不可變的Bean。ImmutableBean允許創(chuàng)建一個(gè)原來(lái)對(duì)象的包裝類(lèi)高镐,這個(gè)包裝類(lèi)是不可變的溉旋,任何改變底層對(duì)象的包裝類(lèi)操作都會(huì)拋出IllegalStateException。但是我們可以通過(guò)直接操作底層對(duì)象來(lái)改變包裝類(lèi)對(duì)象嫉髓。這有點(diǎn)類(lèi)似于Guava中的不可變視圖

為了對(duì)ImmutableBean進(jìn)行測(cè)試观腊,這里需要再引入一個(gè)bean

publicclassSampleBean{privateString value;publicSampleBean(){}publicSampleBean(String value){this.value=value;}publicStringgetValue(){returnvalue;}publicvoidsetValue(String value){this.value=value;}}

然后編寫(xiě)測(cè)試類(lèi)如下:

@Test(expected=IllegalStateException.class)publicvoidtestImmutableBean()throwsException{SampleBean bean=newSampleBean();bean.setValue("Hello world");SampleBean immutableBean=(SampleBean)ImmutableBean.create(bean);//創(chuàng)建不可變類(lèi)Assert.assertEquals("Hello world",immutableBean.getValue());bean.setValue("Hello world, again");//可以通過(guò)底層對(duì)象來(lái)進(jìn)行修改Assert.assertEquals("Hello world, again",immutableBean.getValue());immutableBean.setValue("Hello cglib");//直接修改將throw exception}

Bean generator

cglib提供的一個(gè)操作bean的工具,使用它能夠在運(yùn)行時(shí)動(dòng)態(tài)的創(chuàng)建一個(gè)bean算行。

@TestpublicvoidtestBeanGenerator()throwsException{BeanGenerator beanGenerator=newBeanGenerator();beanGenerator.addProperty("value",String.class);Object myBean=beanGenerator.create();Method setter=myBean.getClass().getMethod("setValue",String.class);setter.invoke(myBean,"Hello cglib");Method getter=myBean.getClass().getMethod("getValue");Assert.assertEquals("Hello cglib",getter.invoke(myBean));}

在上面的代碼中梧油,我們使用cglib動(dòng)態(tài)的創(chuàng)建了一個(gè)和SampleBean相同的Bean對(duì)象,包含一個(gè)屬性value以及getter纱意、setter方法

Bean Copier

cglib提供的能夠從一個(gè)bean復(fù)制到另一個(gè)bean中婶溯,而且其還提供了一個(gè)轉(zhuǎn)換器,用來(lái)在轉(zhuǎn)換的時(shí)候?qū)ean的屬性進(jìn)行操作偷霉。

publicclassOtherSampleBean{privateString value;publicStringgetValue(){returnvalue;}publicvoidsetValue(String value){this.value=value;}}

@TestpublicvoidtestBeanCopier()throwsException{BeanCopier copier=BeanCopier.create(SampleBean.class,OtherSampleBean.class,false);//設(shè)置為true,則使用converterSampleBean myBean=newSampleBean();myBean.setValue("Hello cglib");OtherSampleBean otherBean=newOtherSampleBean();copier.copy(myBean,otherBean,null);//設(shè)置為true褐筛,則傳入converter指明怎么進(jìn)行轉(zhuǎn)換assertEquals("Hello cglib",otherBean.getValue());}

BulkBean

相比于BeanCopier类少,BulkBean將copy的動(dòng)作拆分為getPropertyValues和setPropertyValues兩個(gè)方法,允許自定義處理屬性

@TestpublicvoidtestBulkBean()throwsException{BulkBean bulkBean=BulkBean.create(SampleBean.class,newString[]{"getValue"},newString[]{"setValue"},newClass[]{String.class});SampleBean bean=newSampleBean();bean.setValue("Hello world");Object[]propertyValues=bulkBean.getPropertyValues(bean);assertEquals(1,bulkBean.getPropertyValues(bean).length);assertEquals("Hello world",bulkBean.getPropertyValues(bean)[0]);bulkBean.setPropertyValues(bean,newObject[]{"Hello cglib"});assertEquals("Hello cglib",bean.getValue());}

使用注意:

1. 避免每次進(jìn)行BulkBean.create創(chuàng)建對(duì)象渔扎,一般將其聲明為static的

2. 應(yīng)用場(chǎng)景:針對(duì)特定屬性的get,set操作硫狞,一般適用通過(guò)xml配置注入和注出的屬性,運(yùn)行時(shí)才確定處理的Source,Target類(lèi)晃痴,只需要關(guān)注屬性名即可残吩。

BeanMap

BeanMap類(lèi)實(shí)現(xiàn)了Java Map,將一個(gè)bean對(duì)象中的所有屬性轉(zhuǎn)換為一個(gè)String-to-Obejct的Java Map

@TestpublicvoidtestBeanMap()throwsException{BeanGenerator generator=newBeanGenerator();generator.addProperty("username",String.class);generator.addProperty("password",String.class);Object bean=generator.create();Method setUserName=bean.getClass().getMethod("setUsername",String.class);Method setPassword=bean.getClass().getMethod("setPassword",String.class);setUserName.invoke(bean,"admin");setPassword.invoke(bean,"password");BeanMap map=BeanMap.create(bean);Assert.assertEquals("admin",map.get("username"));Assert.assertEquals("password",map.get("password"));}

我們使用BeanGenerator生成了一個(gè)含有兩個(gè)屬性的Java Bean倘核,對(duì)其進(jìn)行賦值操作后泣侮,生成了一個(gè)BeanMap對(duì)象,通過(guò)獲取值來(lái)進(jìn)行驗(yàn)證

keyFactory

keyFactory類(lèi)用來(lái)動(dòng)態(tài)生成接口的實(shí)例紧唱,接口需要只包含一個(gè)newInstance方法活尊,返回一個(gè)Object隶校。keyFactory為構(gòu)造出來(lái)的實(shí)例動(dòng)態(tài)生成了Object.equals和Object.hashCode方法,能夠確保相同的參數(shù)構(gòu)造出的實(shí)例為單例的蛹锰。

publicinterfaceSampleKeyFactory{ObjectnewInstance(String first,intsecond);}

我們首先構(gòu)造一個(gè)滿(mǎn)足條件的接口深胳,然后進(jìn)行測(cè)試

@TestpublicvoidtestKeyFactory()throwsException{SampleKeyFactory keyFactory=(SampleKeyFactory)KeyFactory.create(SampleKeyFactory.class);Object key=keyFactory.newInstance("foo",42);Object key1=keyFactory.newInstance("foo",42);Assert.assertEquals(key,key1);//測(cè)試參數(shù)相同,結(jié)果是否相等}

Mixin(混合)

Mixin能夠讓我們將多個(gè)對(duì)象整合到一個(gè)對(duì)象中去铜犬,前提是這些對(duì)象必須是接口的實(shí)現(xiàn)舞终。可能這樣說(shuō)比較晦澀癣猾,以代碼為例:

publicclassMixinInterfaceTest{interfaceInterface1{Stringfirst();}interfaceInterface2{Stringsecond();}classClass1implementsInterface1{@OverridepublicStringfirst(){return"first";}}classClass2implementsInterface2{@OverridepublicStringsecond(){return"second";}}interfaceMixinInterfaceextendsInterface1,Interface2{}

@TestpublicvoidtestMixin()throwsException{Mixin mixin=Mixin.create(newClass[]{Interface1.class,Interface2.class,MixinInterface.class},newObject[]{newClass1(),newClass2()});MixinInterface mixinDelegate=(MixinInterface)mixin;assertEquals("first",mixinDelegate.first());assertEquals("second",mixinDelegate.second());}}

Mixin類(lèi)比較尷尬敛劝,因?yàn)樗驧inix的類(lèi)(例如MixinInterface)實(shí)現(xiàn)一些接口。既然被Minix的類(lèi)已經(jīng)實(shí)現(xiàn)了相應(yīng)的接口煎谍,那么我就直接可以通過(guò)純Java的方式實(shí)現(xiàn)攘蔽,沒(méi)有必要使用Minix類(lèi)。

String switcher

用來(lái)模擬一個(gè)String到int類(lèi)型的Map類(lèi)型呐粘。如果在Java7以后的版本中满俗,類(lèi)似一個(gè)switch語(yǔ)句。

@TestpublicvoidtestStringSwitcher()throwsException{String[]strings=newString[]{"one","two"};int[]values=newint[]{10,20};StringSwitcher stringSwitcher=StringSwitcher.create(strings,values,true);assertEquals(10,stringSwitcher.intValue("one"));assertEquals(20,stringSwitcher.intValue("two"));assertEquals(-1,stringSwitcher.intValue("three"));}

Interface Maker

正如名字所言作岖,Interface Maker用來(lái)創(chuàng)建一個(gè)新的Interface

@TestpublicvoidtestInterfaceMarker()throwsException{Signature signature=newSignature("foo",Type.DOUBLE_TYPE,newType[]{Type.INT_TYPE});InterfaceMaker interfaceMaker=newInterfaceMaker();interfaceMaker.add(signature,newType[0]);Classiface=interfaceMaker.create();assertEquals(1,iface.getMethods().length);assertEquals("foo",iface.getMethods()[0].getName());assertEquals(double.class,iface.getMethods()[0].getReturnType());}

上述的Interface Maker創(chuàng)建的接口中只含有一個(gè)方法唆垃,簽名為double foo(int)。Interface Maker與上面介紹的其他類(lèi)不同痘儡,它依賴(lài)ASM中的Type類(lèi)型辕万。由于接口僅僅只用做在編譯時(shí)期進(jìn)行類(lèi)型檢查,因此在一個(gè)運(yùn)行的應(yīng)用中動(dòng)態(tài)的創(chuàng)建接口沒(méi)有什么作用沉删。但是InterfaceMaker可以用來(lái)自動(dòng)生成代碼渐尿,為以后的開(kāi)發(fā)做準(zhǔn)備。

Method delegate

MethodDelegate主要用來(lái)對(duì)方法進(jìn)行代理

interfaceBeanDelegate{StringgetValueFromDelegate();}

@TestpublicvoidtestMethodDelegate()throwsException{SampleBean bean=newSampleBean();bean.setValue("Hello cglib");BeanDelegate delegate=(BeanDelegate)MethodDelegate.create(bean,"getValue",BeanDelegate.class);assertEquals("Hello cglib",delegate.getValueFromDelegate());}

**關(guān)于Method.create的參數(shù)說(shuō)明: **

第二個(gè)參數(shù)為即將被代理的方法? 第一個(gè)參數(shù)必須是一個(gè)無(wú)參數(shù)構(gòu)造的bean矾瑰。因此MethodDelegate.create并不是你想象的那么有用? 第三個(gè)參數(shù)為只含有一個(gè)方法的接口砖茸。當(dāng)這個(gè)接口中的方法被調(diào)用的時(shí)候,將會(huì)調(diào)用第一個(gè)參數(shù)所指向bean的第二個(gè)參數(shù)方法

**缺點(diǎn): **

為每一個(gè)代理類(lèi)創(chuàng)建了一個(gè)新的類(lèi)殴穴,這樣可能會(huì)占用大量的永久代堆內(nèi)存

你不能代理需要參數(shù)的方法

如果你定義的接口中的方法需要參數(shù)凉夯,那么代理將不會(huì)工作,并且也不會(huì)拋出異常采幌;如果你的接口中方法需要其他的返回類(lèi)型劲够,那么將拋出IllegalArgumentException

MulticastDelegate

多重代理和方法代理差不多,都是將代理類(lèi)方法的調(diào)用委托給被代理類(lèi)休傍。使用前提是需要一個(gè)接口征绎,以及一個(gè)類(lèi)實(shí)現(xiàn)了該接口,通過(guò)這種interface的繼承關(guān)系,我們能夠?qū)⒔涌谏戏椒ǖ恼{(diào)用分散給各個(gè)實(shí)現(xiàn)類(lèi)上面去尊残。

多重代理的缺點(diǎn)是接口只能含有一個(gè)方法炒瘸,如果被代理的方法擁有返回值淤堵,那么調(diào)用代理類(lèi)的返回值為最后一個(gè)添加的被代理類(lèi)的方法返回值。

publicinterfaceDelegatationProvider{voidsetValue(String value);}publicclassSimpleMulticastBeanimplementsDelegatationProvider{privateString value;@OverridepublicvoidsetValue(String value){this.value=value;}publicStringgetValue(){returnvalue;}}

@TestpublicvoidtestMulticastDelegate()throwsException{MulticastDelegate multicastDelegate=MulticastDelegate.create(DelegatationProvider.class);SimpleMulticastBean first=newSimpleMulticastBean();SimpleMulticastBean second=newSimpleMulticastBean();multicastDelegate=multicastDelegate.add(first);multicastDelegate=multicastDelegate.add(second);DelegatationProvider provider=(DelegatationProvider)multicastDelegate;provider.setValue("Hello world");assertEquals("Hello world",first.getValue());assertEquals("Hello world",second.getValue());}

Constructor delegate

為了對(duì)構(gòu)造函數(shù)進(jìn)行代理顷扩,我們需要一個(gè)接口拐邪,這個(gè)接口只含有一個(gè)Object newInstance(…)方法,用來(lái)調(diào)用相應(yīng)的構(gòu)造函數(shù)

interfaceSampleBeanConstructorDelegate{ObjectnewInstance(String value);}/**

* 對(duì)構(gòu)造函數(shù)進(jìn)行代理

* @throws Exception

*/@TestpublicvoidtestConstructorDelegate()throwsException{SampleBeanConstructorDelegate constructorDelegate=(SampleBeanConstructorDelegate)ConstructorDelegate.create(SampleBean.class,SampleBeanConstructorDelegate.class);SampleBean bean=(SampleBean)constructorDelegate.newInstance("Hello world");assertTrue(SampleBean.class.isAssignableFrom(bean.getClass()));System.out.println(bean.getValue());}

Parallel Sorter(并行排序器)

能夠?qū)Χ鄠€(gè)數(shù)組同時(shí)進(jìn)行排序隘截,目前實(shí)現(xiàn)的算法有歸并排序和快速排序

@TestpublicvoidtestParallelSorter()throwsException{Integer[][]value={{4,3,9,0},{2,1,6,0}};ParallelSorter.create(value).mergeSort(0);for(Integer[]row:value){intformer=-1;for(intval:row){assertTrue(former<val);former=val;}}}

FastClass

顧明思義扎阶,F(xiàn)astClass就是對(duì)Class對(duì)象進(jìn)行特定的處理,比如通過(guò)數(shù)組保存method引用婶芭,因此FastClass引出了一個(gè)index下標(biāo)的新概念东臀,比如getIndex(String name, Class[] parameterTypes)就是以前的獲取method的方法。通過(guò)數(shù)組存儲(chǔ)method,constructor等class信息犀农,從而將原先的反射調(diào)用惰赋,轉(zhuǎn)化為class.index的直接調(diào)用,從而體現(xiàn)所謂的FastClass呵哨。

@TestpublicvoidtestFastClass()throwsException{FastClass fastClass=FastClass.create(SampleBean.class);FastMethod fastMethod=fastClass.getMethod("getValue",newClass[0]);SampleBean bean=newSampleBean();bean.setValue("Hello world");assertEquals("Hello world",fastMethod.invoke(bean,newObject[0]));}

注意

由于CGLIB的大部分類(lèi)是直接對(duì)Java字節(jié)碼進(jìn)行操作赁濒,這樣生成的類(lèi)會(huì)在Java的永久堆中。如果動(dòng)態(tài)代理操作過(guò)多孟害,容易造成永久堆滿(mǎn)拒炎,觸發(fā)OutOfMemory異常。

CGLIB和Java動(dòng)態(tài)代理的區(qū)別

Java動(dòng)態(tài)代理只能夠?qū)涌谶M(jìn)行代理挨务,不能對(duì)普通的類(lèi)進(jìn)行代理(因?yàn)樗猩傻拇眍?lèi)的父類(lèi)為Proxy击你,Java類(lèi)繼承機(jī)制不允許多重繼承);CGLIB能夠代理普通類(lèi)谎柄;

Java動(dòng)態(tài)代理使用Java原生的反射API進(jìn)行操作丁侄,在生成類(lèi)上比較高效;CGLIB使用ASM框架直接對(duì)字節(jié)碼進(jìn)行操作朝巫,在類(lèi)的執(zhí)行過(guò)程中比較高效


老九學(xué)堂出品绒障,轉(zhuǎn)載請(qǐng)私信哦

對(duì)于文章內(nèi)容有不理解的可以添加老九君個(gè)人QQ:614940318,請(qǐng)備注來(lái)自簡(jiǎn)書(shū)

老九學(xué)堂免費(fèi)C捍歪、C++、Java課程地址:

https://study.163.com/courses-search?keyword=%E8%80%81%E4%B9%9D%E5%AD%A6%E5%A0%82

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鸵钝,一起剝皮案震驚了整個(gè)濱河市糙臼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌恩商,老刑警劉巖变逃,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異怠堪,居然都是意外死亡揽乱,警方通過(guò)查閱死者的電腦和手機(jī)名眉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)凰棉,“玉大人损拢,你說(shuō)我怎么就攤上這事∪鱿” “怎么了福压?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)或舞。 經(jīng)常有香客問(wèn)我荆姆,道長(zhǎng),這世上最難降的妖魔是什么映凳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任胆筒,我火速辦了婚禮,結(jié)果婚禮上诈豌,老公的妹妹穿的比我還像新娘仆救。我一直安慰自己,他們只是感情好队询,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布派桩。 她就那樣靜靜地躺著,像睡著了一般蚌斩。 火紅的嫁衣襯著肌膚如雪铆惑。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,785評(píng)論 1 290
  • 那天送膳,我揣著相機(jī)與錄音员魏,去河邊找鬼。 笑死叠聋,一個(gè)胖子當(dāng)著我的面吹牛撕阎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播碌补,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼虏束,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了厦章?” 一聲冷哼從身側(cè)響起镇匀,我...
    開(kāi)封第一講書(shū)人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎袜啃,沒(méi)想到半個(gè)月后汗侵,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年晰韵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了发乔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡雪猪,死狀恐怖栏尚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情浪蹂,我是刑警寧澤抵栈,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站坤次,受9級(jí)特大地震影響古劲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缰猴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一产艾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧滑绒,春花似錦闷堡、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至纵势,卻和暖如春踱阿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钦铁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工软舌, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人牛曹。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓佛点,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親黎比。 傳聞我的和親對(duì)象是個(gè)殘疾皇子超营,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容