sap-erp实施心得_实施动态代理-比较
sap-erp實(shí)施心得
有時(shí)需要攔截某些方法調(diào)用,以便每次調(diào)用被攔截方法時(shí)都執(zhí)行自己的邏輯。 如果您不屬于Java EE的CDI領(lǐng)域,并且不想使用諸如Aspectj之類(lèi)的AOP框架,那么您將有一個(gè)簡(jiǎn)單而有效的替代方法。
從1.5版開(kāi)始,JDK附帶了類(lèi)java.lang.reflect.Proxy,該類(lèi)允許您為給定的接口創(chuàng)建動(dòng)態(tài)代理。 每當(dāng)應(yīng)用程序調(diào)用代理上的方法時(shí),都會(huì)調(diào)用位于動(dòng)態(tài)創(chuàng)建的類(lèi)后面的InvocationHandler。 因此,您可以在調(diào)用某個(gè)框架或庫(kù)的代碼之前動(dòng)態(tài)控制執(zhí)行什么代碼。
在JDK的Proxy實(shí)現(xiàn)旁邊,像javassist或cglib這樣的字節(jié)碼框架提供了類(lèi)似的功能。 在這里,您甚至可以對(duì)現(xiàn)有的類(lèi)進(jìn)行子類(lèi)化,并確定要轉(zhuǎn)發(fā)給超類(lèi)的實(shí)現(xiàn)的方法以及要攔截的方法。 當(dāng)然,這會(huì)帶來(lái)項(xiàng)目依賴(lài)的另一個(gè)庫(kù)的負(fù)擔(dān),并且可能需要不時(shí)更新,而運(yùn)行時(shí)環(huán)境中已經(jīng)包含了JDK的Proxy實(shí)現(xiàn)。
因此,讓我們仔細(xì)看看并嘗試這三種選擇。 為了將javassist和cglib的代理與JDK實(shí)現(xiàn)進(jìn)行比較,我們需要一個(gè)由簡(jiǎn)單類(lèi)實(shí)現(xiàn)的接口,因?yàn)镴DK機(jī)制僅支持接口,而沒(méi)有子類(lèi):
public interface IExample {void setName(String name); }public class Example implements IExample {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;} }為了將代理上的方法調(diào)用委托給某個(gè)實(shí)際對(duì)象,我們創(chuàng)建了上面的Example類(lèi)的實(shí)例,并通過(guò)最終聲明的變量在InvocationHandler中調(diào)用它:
final Example example = new Example(); InvocationHandler invocationHandler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return method.invoke(example, args);} }; return (IExample) Proxy.newProxyInstance(JavaProxy.class.getClassLoader(), new Class[]{IExample.class}, invocationHandler);從代碼示例中可以看到,代理的創(chuàng)建非常簡(jiǎn)單:調(diào)用靜態(tài)方法newProxyInstance()并提供ClassLoader,應(yīng)由代理實(shí)現(xiàn)的接口數(shù)組以及InvocationHandler接口的實(shí)例。 為了演示起見(jiàn),我們的實(shí)現(xiàn)僅轉(zhuǎn)發(fā)我們之前創(chuàng)建的Example實(shí)例。 但是,在現(xiàn)實(shí)生活中,您當(dāng)然可以執(zhí)行更高級(jí)的操作,以評(píng)估例如方法名稱(chēng)或其參數(shù)。
現(xiàn)在我們來(lái)看一下使用javassist完成相同操作的方式:
ProxyFactory factory = new ProxyFactory(); factory.setSuperclass(Example.class); Class aClass = factory.createClass(); final IExample newInstance = (IExample) aClass.newInstance(); MethodHandler methodHandler = new MethodHandler() {@Overridepublic Object invoke(Object self, Method overridden, Method proceed, Object[] args) throws Throwable {return proceed.invoke(newInstance, args);} }; ((ProxyObject)newInstance).setHandler(methodHandler); return newInstance;在這里,我們有一個(gè)ProxyFactory,它想知道應(yīng)該為哪個(gè)類(lèi)創(chuàng)建子類(lèi)。 然后,我們讓ProxyFactory創(chuàng)建一個(gè)整個(gè)類(lèi),該類(lèi)可以根據(jù)需要多次重用。 這里的MethodHandler與InvocationHandler類(lèi)似,后者是為實(shí)例的每次方法調(diào)用而調(diào)用的。 在這里,我們?cè)俅螌⒄{(diào)用轉(zhuǎn)發(fā)到之前創(chuàng)建的Example實(shí)例。
最后但并非最不重要的一點(diǎn),讓我們看一下cglib的代理:
final Example example = new Example(); IExample exampleProxy = (IExample) Enhancer.create(IExample.class, new MethodInterceptor() {@Overridepublic Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {return method.invoke(example, args);} }); return exampleProxy;在cglib世界中,我們有一個(gè)Enhancer類(lèi),可用于通過(guò)MethodInterceptor實(shí)例實(shí)現(xiàn)給定的接口。 回調(diào)方法的實(shí)現(xiàn)看起來(lái)與javassist示例中的實(shí)現(xiàn)非常相似。 我們只是通過(guò)反射API將方法調(diào)用轉(zhuǎn)發(fā)到Example的現(xiàn)有實(shí)例。
現(xiàn)在,我們已經(jīng)看到了三種不同的實(shí)現(xiàn),我們還希望評(píng)估它們的運(yùn)行時(shí)行為。 因此,我們編寫(xiě)了一個(gè)簡(jiǎn)單的單元測(cè)試,它測(cè)量了每個(gè)實(shí)現(xiàn)的執(zhí)行時(shí)間:
@Test public void testPerformance() {final IExample example = JavaProxy.createExample();long measure = TimeMeasurement.measure(new TimeMeasurement.Execution() {@Overridepublic void execute() {for (long i = 0; i < JavassistProxyTest.NUMBER_OF_ITERATIONS; i++) {example.setName("name");}}});System.out.println("Proxy: "+measure+" ms"); }我們選擇大量的迭代,以強(qiáng)調(diào)JVM并讓HotSpot編譯器為經(jīng)常執(zhí)行的段落創(chuàng)建本機(jī)代碼。 下表顯示了三種實(shí)現(xiàn)的平均運(yùn)行時(shí)間:
為了完全顯示代理實(shí)現(xiàn)的影響,該圖表還顯示了對(duì)Example對(duì)象(“無(wú)代理”)進(jìn)行標(biāo)準(zhǔn)方法調(diào)用的執(zhí)行時(shí)間。 首先,我們可以記錄到代理實(shí)現(xiàn)比方法本身的普通調(diào)用慢大約10倍。 但是我們也注意到三種代理解決方案之間的差異。 令人驚訝的是,JDK的Proxy類(lèi)幾乎與cglib實(shí)現(xiàn)一樣快。 只有javassist的退出時(shí)間是cglib的兩倍左右。
結(jié)論:運(yùn)行時(shí)代理易于使用,您有不同的處理方式。 JDK的代理僅支持接口代理,而javassist和cglib允許您對(duì)現(xiàn)有類(lèi)進(jìn)行子類(lèi)化。 代理的運(yùn)行時(shí)行為比標(biāo)準(zhǔn)方法調(diào)用慢大約10倍。 三種解決方案在運(yùn)行時(shí)間方面也有所不同。
翻譯自: https://www.javacodegeeks.com/2014/01/implementing-dynamic-proxies-a-comparison.html
sap-erp實(shí)施心得
總結(jié)
以上是生活随笔為你收集整理的sap-erp实施心得_实施动态代理-比较的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 无人机需要备案吗(无人机免备案)
- 下一篇: 边锋三国杀安卓版体验服(边锋三国杀安卓版