O conceito de AOP
AOP: Programação orientada a aspectos (programação orientada para a seção), a Wikipedia explica a seguinte: o aspecto é um novo mecanismo modular usado para descrever preocupações transversais espalhadas em objetos, classes ou funções. A separação de preocupações transversais das preocupações é o conceito central de programação orientada a tangente. A separação do foco torna o código que resolve problemas específicos de domínio independentes da lógica de negócios. O Código de Lógica de Negócios não contém chamadas para codificar problemas específicos de domínio. A relação entre lógica de negócios e problemas específicos de domínio é encapsulada e mantida através de seções, para que as alterações que foram originalmente dispersas ao longo do aplicativo podem ser bem gerenciadas. Do ponto de vista da AOP, os aplicativos podem ser divididos em preocupações transversais e código lógica de negócios. No desenvolvimento real, essas preocupações transversais geralmente são diretamente incorporadas ao código lógico de negócios. A programação orientada para o rosto é resolver o problema de separar as preocupações transversais da lógica de negócios.
Método de implementação:
A Spring usa o proxy dinâmico do JDK como proxy da AOP por padrão. A falha é que a classe de destino deve implementar uma interface, caso contrário, o proxy dinâmico do JDK não pode ser usado. Se a classe for uma classe e não uma interface, o Spring usará o proxy do CGLIB por padrão. Em relação à diferença entre os dois: o proxy dinâmico do JDK é implementado através do mecanismo de reflexão de Java, a classe de destino deve implementar interfaces e o CGLIB implementa proxy para classes. Seu princípio é gerar dinamicamente uma subclasse para a classe de destino especificada e substituir o aprimoramento da implementação do método, mas como a herança é usada, a classe final modificada não pode ser procurada.
JDK Proxy dinâmico
O proxy dinâmico do JDK gera dinamicamente arquivos de classe de classes de proxy com base na interface implementada pela classe de destino durante a operação do programa. O uso envolve principalmente duas classes:
Interface InvocationHandler: Ele fornece um método invoke(Object obj,Method method, Object[] args) para os implementadores fornecerem implementação lógica de proxy correspondente. Algum processamento especial pode ser realizado na implementação real e os parâmetros são
Objeto obj: a classe de destino que é proxyed
Método do método: Método da classe de destino que precisa ser executado
Objeto [] args: parâmetros do método de destino
Classe de proxy: forneça um método newProxyInstance (ClassLoader loader, Class[] interfaces, InvocationHandler h) para obter a classe de proxy dinâmica
Código de exemplo:
Public Interface OrderService {public void createOrder (); } public class OrderServiceImpl implementa o OrderService {@Override public void createOrder () {System.out.println ("Criar ordem"); }} public class OrderLogger {public void beFeCreateOrder () {System.out.println ("Antes de criar ordem"); } public void AfterCreateOrder () {System.out.println ("Após Create Order"); }} pacote com.sl.aop; importar java.lang.reflect.invocationHandler; importar java.lang.reflect.method; importar java.lang.reflect.proxy; public class ServiceProxy implementa InvocationHandler {Private Object -alvoClass; Private OrderLogger OrderLogger; public ServiceProxy (Object TargetClass, OrderLogger OrderLogger) {this.targetClass = TargetClass; this.OrderLogger = OrderLogger; } // obtenha proxy public Object getDynamicProxy () {return proxy.newproxyInstance (TargetClass.getClass (). GetClassLoader (), // Crie objeto proxy através deste Classloader TargetClass.getClass (). // O método de chamada de proxy dinâmico é o InvocationHandler associado e, finalmente, executa o método real através do método de invocado deste InvocationHandler} // Implementar a lógica de proxy correspondente @Override Public Object Invoke (proxy de objeto, método, método, objeto [] Args) lança arremesso {this.OrderLogger.beforeTorder (); Resultado de objeto = method.invoke (TargetClass, args); this.orderLogger.afterCreateOrder (); resultado de retorno; }}Classe de teste:
pacote com.sl.aop; importar org.junit.test; public class AOPTEST {@Test public void testDynicProxy () {OrderServiceImpl ServiceImpl = new OrderServiceImpl (); OrderLogger Logger = new OrderLogger (); OrderService Service = (OrderService) New ServiceProxy (ServiceImpl, Logger) .getDynamicProxy (); Service.CreateOrder (); }}Resultados em execução:
Na verdade, estou um pouco confuso quando chego a esse ponto. O que Proxy.newProxyInstance() retorna? Onde é chamado o método Invoke? Vamos dar uma olhada no código -fonte do JDK: veja como é o processo de proxy dinâmico DK:
Call Proxy.newProxyInstance()->Proxy.getProxyClass0()->WeakCache.get() de acordo com a função dentro do código-fonte e primeiro localize-o primeiro
Fracascache.class:
public v get (K -Key, P parâmetro) {Objects.RequirenOnNull (parâmetro); ExpungestaleEntries (); Objeto cachekey = cachekey.valueof (chave, refqueue); // Instale preguiçosamente o 2º nível ValuesMap para o cachekey específico ConcurrentMap <Object, Fornecedor <V>> valoresMap = map.get (cacheKey); if (valoresmap == null) {concurrentmap <objeto, fornecedor <V >> OldValuesMap = map.putifabsent (cacheKey, valoresMap = new ConcurrentHashMap <> ()); if (OldValuesMap! = NULL) {valoresMap = OldValuesMap; }} // Crie subcky e recupere o possível fornecedor <V> armazenado por isso // subckey do objeto valoresmap subkey = objects.requiteNononnull (subkeyFactory.Apply (key, parâmetro)); Fornecedor <V> fornecedor = valoresMap.get (Subkey); Fábrica de fábrica = nulo; while (true) {if (fornecedor! = null) {// Fornecedor pode ser uma fábrica ou um cachevalue <V> instância v value = fornecedor.get.get (); if (value! = null) {return value; }} // senão nenhum fornecedor em cache // ou um fornecedor que retornou nulo (pode ser um cachevalue limpo // ou uma fábrica que não foi bem -sucedida na instalação do cachevalue) // construa preguiçosamente uma fábrica se (fábrica == null) {fábrica = nova fábrica (chave, parâmetro, subcheque, valores); } if (fornecedor == null) {fornecedor = valoresmap.putifabsent (subkey, fábrica); if (fornecedor == null) {// Fornecedor de fábrica instalado com sucesso = fábrica; } // caso contrário, tente novamente com o fornecedor vencedor} else {if (valoresmap.replace (subkey, fornecedor, fábrica)) {// substituído com sucesso // cacheentry limpo / fábrica insuficiente // com nosso fornecedor de fábrica = fábrica; } else {// Represente com o fornecedor do fornecedor atual do fornecedor = valoresmap.get (subkey); }}}} Você pode ver o valor de retorno da função; e V value = supplier.get(); Continue a lê -lo e descobri que o jantar = fábrica é na verdade um objeto de fábrica; portanto, continue a ver Factory.get()
public sincronizado v get () {// serialize access // re-check fornecedor <V> fornecedor = valoresmap.get (subkey); se (fornecedor! = this) {// algo mudou enquanto estávamos esperando: // pode ser que fomos substituídos por um cachevalue // ou foram removidos devido à falha -> // retornar NULL para sinalizar fracoscache.get () para tentar // o loop retornar nulo; } // else ainda nós (fornecedor == this) // crie novo valor v value = null; tente {value = objects.RequirenOnNull (valueFactory.Apply (chave, parâmetro)); } finalmente {if (value == null) {// Remova -nos nos valores de falhaMap.Remove (subkey, este); }} // O único caminho a chegar aqui é com o valor não nulo de valor! = null; // Valor de embrulho com Cachevalue (fracos) Cachevalue <V> Cachevalue = new Cachevalue <> (valor); // Tente nos substituir por Cachevalue (isso sempre deve ter sucesso) se (valoresmap.replace (subkey, isto, cachevalue)) {// coloque também em reversemap reverseMap.put (cachevalue, boolean.true); } else {lança novo assertionError ("não deve chegar aqui"); } // nos substituiu com sucesso por um novo Cachevalue -> retornar o valor // embrulhado pelo valor de retorno dele; } Valor de retorno; Em seguida, visualize diretamente a declaração de atribuição: value = Objects.requireNonNull(valueFactory.apply(key, parameter));
O que diabos é o ValueFactory?
public fratCache (Bifunction <k, p,?> subkketfactory, bifunction <k, p, v> valuefactory) {this.subkeyFactory = Objects.RequiRenOnNull (SubkeyFactory); this.valueFactory = Objects.RequirenOnNull (ValueFactory); } private estático final fracarcache <classe de classe, classe <?> [], classe <? >> proxyclasscache = new frwawcache <> (new keyFactory (), new proxyclassFactory ()); Você pode saber que o ValueFactory é um objeto de tipo proxyclassFactory e visualiza diretamente ProxyClassFactory. Apply() Método ProxyClassFactory. Apply()
Classe public <?> Aplicar (ClassLoader carregador, classe <?> [] interfaces) {map <classe <?>, boolean> interfaceSet = new IdentityHashmap <> (interfaces.lengthing); para (classe <?> intf: interfaces) { / * * Verifique se o carregador da classe resolve o nome dessa interface * para o mesmo objeto de classe. */ Classe <?> InterfaceClass = null; tente {interfaceclass = class.ForName (intf.getName (), false, carregador); } catch (classNotFoundException e) {} if (interfaceclass! = intf) {lança new ilegalArgumentException (intf + "não é visível do carregador de classe"); } / * * Verifique se o objeto de classe realmente representa uma interface *. */ se (! } / * * Verifique se essa interface não é uma duplicata. */ if (interfaceSet.put (interfaceclass, boolean.true)! = null) {lança new ilegalArgumentException ("interface repetida:" + interfaceclass.getName ()); }} String proxypkg = null; // Modifier.Final; / * * Registre o pacote de uma interface de proxy não pública para que a classe * proxy seja definida no mesmo pacote. Verifique se * todas as interfaces de proxy não públicas estão no mesmo pacote. */ for (classe <?> intf: interfaces) {int flags = intf.getModifiers (); if (! modifier.ispublic (sinalizadores)) {accessflags = modifier.Final; Nome da string = intf.getName (); int n = name.LastIndexOf ('.'); String pkg = ((n == -1)? "": Name.substring (0, n + 1)); if (proxypkg == null) {proxypkg = pkg; } else se (! }}}} if (proxypkg == null) {// Se não houver interfaces de proxy não public, use com.sun.proxy package proxypkg = refletutil.proxy_package + "."; } / * * Escolha um nome para a classe proxy gerar. */ long num = nextUnikeNumber.getAndIncrement (); String proxyname = proxypkg + proxyclassNameRefix + num; / * * Gere a classe proxy especificada. */ byte [] proxyclassFile = proxygenerator.geReateProxyclass (proxyname, interfaces, accessflags); tente {return definitivamenteClass0 (carregador, proxyname, proxyclassFile, 0, proxyclassfile.length); } Catch (ClassFormaterror e) { / * * Um ClassFormaterror aqui significa que (exceto os bugs no código de geração da classe de proxy), havia outro aspecto * inválido dos argumentos fornecidos à criação de classe * de proxy * (como limitações de máquina virtual * excedidas). */ jogue nova ilegalArgumentException (e.toString ()); }}}Desenhe diretamente os pontos -chave:
byte [] proxyclassFile = proxygenerator.geReateProxyclass (proxyname, interfaces, accessflags); return defineclass0 (carregador, proxyname, proxyclassfile, 0, proxyclassfile.length);
Chamar ProxyGenerator.generateProxyClass Finalmente gera dinamicamente uma classe de proxy, mas parece que em nenhum lugar é chamado de Invoke; Consulte o artigo csdn: //www.vevb.com/article/118935.htm, tente produzir o bytecode binário gerado dinamicamente localmente e descompilar para ver o que é. O código de teste é o seguinte:
public class AOPTEST {@Test public void testDynamicProxy () {OrderServiceImpl ServiceImpl = new OrderServiceImpl (); OrderLogger Logger = new OrderLogger (); OrderService Service = (OrderService) New ServiceProxy (ServiceImpl, Logger) .getDynamicProxy (); Service.CreateOrder (); // Classe de proxy dinâmica de saída Bytecode CreateProxyclassFile (); } private estático void createproxyclassFile () {string name = "proxyObject"; byte [] data = proxyGenerator.geReReProxyclass (nome, nova classe [] {OrderService.class}); FileOutputStream Out = NULL; tente {out = new FileOutputStream (nome+". classe"); System.out.println ((novo arquivo ("hello")). GetAbsolutepath ()); out.write (dados); } catch (filenotfoundException e) {e.printStackTrace (); } catch (ioexception e) {e.printStackTrace (); } finalmente {if (null! = out) tente {out.close (); } catch (ioexception e) {e.printStackTrace (); }}}}}}Use a ferramenta Java Decompiler para descompilar este arquivo de classe binária:
Classe de proxy dinâmica específica proxyobject.java:
importar com.sl.aop.orderService; importar java.lang.reflect.invocationHandler; importar java.lang.reflect.method; importar java.lang.reflect.proxy; a classificação final; Método estático privado m2; Método estático privado m3; Método estático privado m0; public proxyObject (InvocationHandler paraminvocationHandler) {super (paraminvocationHandler); } public final boolean é igual (objeto paramobject) {try {return ((boolean) this.h.invoke (this, m1, novo objeto [] {paramobject})). booleanValue (); } catch (error | RUNTimeException localError) {Throw localError; } catch (localwlowable) {lança uma nova não declaração de abastecimento (local de trabalho); }} public final string tostring () {try {return (string) this.h.invoke (this, m2, nulo); } catch (error | RUNTimeException localError) {Throw localError; } catch (localwlowable) {lança uma nova não declaração de abastecimento (local de trabalho); }} public final void createOrder () {try {this.h.invoke (this, m3, null); retornar; } catch (error | RUNTimeException localError) {Throw localError; } catch (localwlowable) {lança uma nova não declaração de abastecimento (local de trabalho); }} public final int hashCode () {try {return ((integer) this.h.invoke (this, m0, null)). intvalue (); } catch (error | RUNTimeException localError) {Throw localError; } catch (localwlowable) {lança uma nova não declaração de abastecimento (local de trabalho); }} static {try {m1 = class.ForName ("java.lang.object"). m2 = classe.ForName ("java.lang.object"). getMethod ("tostring", nova classe [0]); m3 = classe.ForName ("com.sl.aop.orderService"). getMethod ("createOrder", nova classe [0]); m0 = classe.ForName ("java.lang.object"). getMethod ("hashcode", nova classe [0]); retornar; } Catch (NosuchMethodException LocalnosuchMethodException) {tire o novo NosuchMethoderror (LocalnosuchMethodException.getMessage ()); } Catch (ClassNotFoundException LocalClassNotFoundException) {THLHET NOVA NOCLASSDEFFONDERROR (LOCALCLASSNOTFOUNDEXCECCECTION.GETMESSAGE ()); }}Finalmente vi a parte sobre invocar:
public final void createOrder () {try {this.h.invoke (this, m3, null); retornar; } catch (error | RUNTimeException localError) {Throw localError; } catch (localwlowable) {lança uma nova não declaração de abastecimento (local de trabalho); }}De fato, a classe de proxy dinâmica herda do proxy e implementa a interface herdada pela classe de destino. O método Invoke é chamado no método CreateOrder, que implementa a implantação da lógica seccional. Aqui também respondemos a uma pergunta, por que a classe de destino do proxy dinâmico do JDK deve implementar a interface, porque a classe Proxy é realmente destinada ao proxy da interface, não à classe. A classe dinâmica de proxy se herda do proxy, e o Java não permite herança múltipla. A classe de proxy dinâmica e a classe de destino implementam as interfaces, respectivamente. A classe Proxy realiza a chamada para o método da classe de destino através do InvocationHandler.inVoke.
Proxy dinâmico do CGLIB
O proxy do CGLIB usa uma estrutura de processamento de bytecode para converter o bytecode e gerar novas classes e usa técnicas de interceptação de métodos em subclasses para interceptar todos os métodos de classe dos pais para implementar a lógica cruzada, o que é mais eficiente que o proxy dinâmico JDK usando a tecnologia de reflexão. No entanto, como o princípio do CGLIB é gerar dinamicamente as classes de proxy de subclasse para a classe de destino, ele não pode ser procurado para métodos declarados como final. Seu uso envolve principalmente duas categorias:
MethodIntercept Interface: Esta interface fornece um método intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) usado principalmente para interceptar a chamada dos métodos de classe de destino.
Objeto arg0: a classe de destino que está sendo proxiada
Método arg1, método delegado
Objeto [] arg2, parâmetros do método
MethodProxy Arg3: Methodproxy Object of Proxy Method
Classe de Enhancer: Usado para criar a classe proxy
Exemplo:
Implementar a interface do MethodIntercept. Quando a classe de proxy chama um método, o CGLIB devolve o método da interface do MethodInterceptor, tecendo assim a lógica da superfície.
pacote com.sl.aop; importar java.lang.reflect.method; importar org.springframework.cglib.proxy.enhancer; importar org.springframework.cglib.proxy.methinterceptor; importer; {objeto privado TargetClass; Private OrderLogger OrderLogger; public CGlibServiceProxy (Object TargetClass, OrderLogger OrderLogger) {this.TargetClass = TargetClass; this.OrderLogger = OrderLogger; } / *** Crie um objeto proxy** / public Object getInstance () {intensificador intensificador = new aprimor (); // Defina a classe de destino (classe que precisa ser proxyed) intensificador.SetSuperclass (this.targetclass.getclass ()); // Método de retorno de chamada aprimorador.setCallback (this); // Crie Returno de Retorno de Objeto Proxy EIDENCE.CREATE (); } / *** Interceptar todos os métodos de classe de destino** / @Override Public Object Intercept (objeto arg0, método arg1, objeto [] arg2, métodproxy arg3) lança arremesso {orderLogger.beforeCreateOrder (); Objeto o1 = arg3.invokesuper (arg0, arg2); OrderLogger.afterCreateOrder (); retornar o1; }}Método de teste:
public void testDynamicProxy () {System.SetProperty (DebuggingClasswriter.debug_location_property, "d: // class"); OrderServiceImpl ServiceImpl = new OrderServiceImpl (); OrderLogger Logger = new OrderLogger (); CGLIBSERVICEPROXY proxy = new CGlibServiceProxy (ServiceImpl, Logger); // Crie uma classe proxy gerando subclasses OrderServiceImpl proxyimp = (OrderServiceImpl) proxy.getInstance (); proxyimp.CreateOrder (); }resultado:
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://class"); saída CLIB CLIB DINAMICA DE PROXY CLASSE para o diretório especificado, descompile e verifique a face verdadeira da classe de proxy:
pacote com.sl.aop; importar com.sl.aop.orderServiceImpl; importar java.lang.reflect.method; importar org.springframework.cglib.core.reflectutils; importação org.springframework.cglib.core.clib. org.springframework.cglib.proxy.Factory;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;public class OrderServiceImpl$$EnhancerByCGLIB$$17779aa4 extends OrderServiceImpl implements Factory { private boolean CGLIB $ LIBRE; objeto estático público cglib $ factory_data; private estático final threadlocal cglib $ thread_callbacks; Retorno de chamada final estático privado [] CGLIB $ static_callbacks; Método privado CLIB $ callback_0; Objeto estático privado CGLIB $ Callback_Filter; Método final estático privado CGLIB $ createOrder $ 0 $ Método; Método final estático privado Proxy CGLIB $ createOrder $ 0 $ proxy; Objeto final estático privado [] CGLIB $ emptyArgs; Método final estático privado CGLIB $ é igual a $ 1 $ Método; Método final estático privado CGLIB $ é igual a $ 1 $ proxy; Método final estático privado CGLIB $ ToString $ 2 $ Método; Método final estático privado PROXY CGLIB $ ToString $ 2 $ Proxy; Método final estático privado CGLIB $ HASHCODE $ 3 $ Método; Método final estático privado CGLIB $ HASHCODE $ 3 $ Proxy; Método final estático privado MethodCglib $ clone $ 4 $ Método; Método final estático privado PROXY CGLIB $ CLONE $ 4 $ Proxy; estático void cglib $ statichook1 () {cglib $ thread_callbacks = new Threadlocal (); CGLIB $ emptyArgs = novo objeto [0]; Classe var0 = classe.ForName ("com.sl.aop.orderServiceImpl $$ aprimorycglib $$ 17779AA4"); Classe var1; Método [] var10000 = refletiTils.findMethods (new String [] {"equals", "(ljava/lang/object;) z", "toString", "() ljava/lang/string;", "hashcode", "() i", "clone", "() ljava; Class.ForName ("java.lang.Object")). GetDecLaredMethods ()); CGLIB $ é igual a $ 1 $ Método = VAR10000 [0]; CGLIB $ é igual a $ 1 $ proxy = MethodProxy.create (var1, var0 "(ljava/lang/objeto;) z", "é igual", "cglib $ igual a $ 1"); CGLIB $ ToString $ 2 $ Método = VAR10000 [1]; Cglib $ toString $ 2 $ proxy = métodProxy.create (var1, var0, "() ljava/lang/string;", "tostring", "cglib $ tostring $ 2"); CGLIB $ HASHCODE $ 3 $ Método = VAR10000 [2]; CGLIB $ HASHCODE $ 3 $ proxy = MethodProxy.create (var1, var0, "() i", "hashcode", "cglib $ hashcode $ 3"); CGLIB $ CLONE $ 4 $ Método = VAR10000 [3]; Cglib $ clone $ 4 $ proxy = métodProxy.create (var1, var0, "() ljava/lang/objeto;", "clone", "cglib $ clone $ 4"); CGLIB $ createOrder $ 0 $ Método = RefletUtils.FindMethods (new String [] {"CreateOrder", "() V"}, (var1 = classe.ForName ("com.sl.aop.orderServiceImpl")). GetDecLaredMethods ()) [0]; CGLIB $ createOrder $ 0 $ proxy = MethodProxy.create (var1, var0, "() v", "CreateOrder", "CGLIB $ CreateOrder $ 0"); } Void final CGLIB $ createOrder $ 0 () {super.CreateOrder (); } public final void createOrder () {MethodInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } if (var10000! = null) {var10000.Intercept (this, cGLIB $ createOrder $ 0 $ Método, cGLIB $ emptyArgs, cGLIB $ createOrder $ 0 $ proxy); } else {super.CreateOrder (); }} final CGLIB BOOLEAN $ igual a $ 1 (objeto var1) {return super.equals (var1); } public final boolean é igual (objeto var1) {MethodInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } if (var10000! = null) {objeto var2 = var10000.Intercept (this, cglib $ é igual a $ 1 $ Método, novo objeto [] {var1}, cglib $ é igual a $ 1 $ proxy); retornar var2 == null? false: ((boolean) var2) .BooleanValue (); } else {return super.equals (var1); }} string final cglib $ tostring $ 2 () {return super.toString (); } public final string tostring () {MethodInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } return var10000! = null? (string) var10000.intercept (this, cglib $ tostring $ 2 $ método, cglib $ emptyargs, cglib $ toString $ 2 $ proxy): super.toString (); } final int cGlib $ hashcode $ 3 () {return super.hashcode (); } public final int hashCode () {MethodInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } if (var10000! = null) {objeto var1 = var10000.Intercept (this, cglib $ hashcode $ 3 $ Método, cglib $ emptyArgs, cglib $ hashcode $ 3 $ proxy); return var1 == null? 0: ((número) var1) .IntValue (); } else {return super.hashcode (); }} Objeto final CGLIB $ clone $ 4 () lança clonenotsupportedException {return super.clone (); } Protegido Final Object clone () lança clonenotsupportedException {MethodInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } retornar var10000! = null? var10000.intercept (this, cglib $ clone $ 4 $ Método, cglib $ emptyargs, cglib $ clone $ 4 $ proxy): super.clone (); } Método estático público PROXY CGLIB $ findMethOdProxy (assinatura var0) {string var10000 = var0.toString (); switch (var10000.hashcode ()) {case -2138148221: if (var10000.equals ("createOrder () v")) {return cglib $ createOrder $ 0 $ proxy; } quebrar; Caso -508378822: if (var10000.equals ("clone () ljava/lang/object;")) {return cglib $ clone $ 4 $ proxy; } quebrar; Caso 1826985398: if (var10000.equals ("é igual a (ljava/lang/objeto;) z")) {return cglib $ é igual a $ 1 $ proxy; } quebrar; case 1913648695: if (var10000.equals ("tostring () ljava/lang/string;"))) {return cglib $ tostring $ 2 $ proxy; } quebrar; case 1984935277: if (var10000.equals ("hashcode () i")) {return cglib $ hashcode $ 3 $ proxy; }} retornar nulo; } public OrderServiceImpl $$ ENFERCHERBYCGLIB $$ 17779AA4 () {CGLIB $ bind_Callbacks (this); } public static void CGLIB $ set_thread_callbacks (retorno de chamada [] var0) {cglib $ thread_callbacks.set (var0); } public static void CGLIB $ set_static_callbacks (retorno de chamada [] var0) {cglib $ static_callbacks = var0; } private estático vazio final cGLIB $ bind_callbacks (objeto var0) {OrdeserviceImpl $$ ENCERBYCGLIB $$ 17779AA4 VAR1 = (OrderServiceImpl $$ ENIFERBYCGLIB $$ 17779AA4) VAR0; if (! var1.cglib $ bound) {var1.cglib $ bound = true; Objeto var10000 = cglib $ thread_callbacks.get (); if (var10000 == null) {var10000 = cglib $ static_callbacks; if (cglib $ static_callbacks == null) {return; }} var1.cglib $ callback_0 = (MethodInterceptor) ((retorno de chamada []) var10000) [0]; }} public objeto newInstance (retorno de chamada [] var1) {cglib $ set_thread_callbacks (var1); OrderServiceImpl $$ ENIFERBYCGLIB $$ 17779AA4 VAR10000 = NOVO ORDERSERVICEIMPL $$ ENDERCHERBYCGLIB $$ 17779AA4 (); Cglib $ set_thread_callbacks ((retorno de chamada []) null); retornar VAR10000; } public objeto newInstance (retorno de chamada var1) {cglib $ set_thread_callbacks (novo retorno de chamada [] {var1}); OrderServiceImpl $$ ENIFERBYCGLIB $$ 17779AA4 VAR10000 = NOVO ORDERSERVICEIMPL $$ ENDERCHERBYCGLIB $$ 17779AA4 (); Cglib $ set_thread_callbacks ((retorno de chamada []) null); retornar VAR10000; } public objeto newInstance (classe [] var1, objeto [] var2, retorno de chamada [] var3) {cglib $ set_thread_callbacks (var3); OrderServiceImpl $$ ENFERBERBYCGLIB $$ 17779AA4 VAR10000 = NOVO ORDERSERVICEIMPL $$ ENDERCHERBYCGLIB $$ 17779AA4; switch (var1.length) {case 0: var10000. <ingit> (); Cglib $ set_thread_callbacks ((retorno de chamada []) null); retornar VAR10000; Padrão: jogue novo IllegalargumentException ("Construtor não encontrado"); }} public RinBack GetCallback (int var1) {cglib $ bind_callbacks (this); MethodInterceptor VAR10000; switch (var1) {case 0: var10000 = this.cglib $ callback_0; quebrar; padrão: var10000 = nulo; } retornar var10000; } public void setCallback (int var1, retorno de chamada var2) {switch (var1) {case 0: this.cglib $ callback_0 = (métodinterceptor) var2; Padrão:}} public Rallback [] getCallbacks () {cglib $ bind_callbacks (this); retornar novo retorno de chamada [] {this.cglib $ callback_0}; } public void setCallbacks (retorno de chamada [] var1) {this.cglib $ callback_0 = (MethodInterceptor) var1 [0]; } static {cglib $ statichook1 (); }}No código acima, você pode ver que a classe Proxy OrderServiceImpl $$ ENIFERBYCGLIB $$ 17779AA4 herda a classe Target OrderServiceImpl e implementa a fábrica da interface. Na classe Proxy, dois métodos CGLIB $ CreateOrder $ 0 e CreateOrder são gerados:
O método CGLIB $ CreateOrder $ 0 chama diretamente o supper.createOrder da classe de destino.CreateOrder
O método CreateOrder conta primeiro se o retorno de chamada da interface MethodInterceptor é implementado. Se existir, o método de interface do MethodInterceptor é chamado. De acordo com a implementação anterior, a chamada para o método de destino é implementada. Object o1 = arg3.invokeSuper(arg0, arg2) é implementado. O Invokesuper é na verdade CGLIB$createOrder$0() da classe proxy que é diretamente chamado, e a classe CreateOrder de destino é finalmente chamada.
Comparação de dois agentes
JDK Proxy dinâmico:
A classe de proxy e a classe Delegate implementam a mesma interface. Ele implementa principalmente o InvocationHandler através da classe de proxy e reescreve o método de invocamento para executar o proxy dinâmico. O método será aprimorado no método de invocamento. As vantagens do método: nenhuma interface codificada é necessária e a taxa de reutilização de código é alta. Desvantagens: somente a classe Delegate que pode ser implementada pela interface
Proxy dinâmico do CGLIB:
A classe de proxy assume a classe Delegate como sua classe pai e cria dois métodos para os métodos de delegados não finais. Um é o mesmo método que a assinatura do método delegado, que chamará o método delegado por meio do super no método; O outro é o método exclusivo da classe proxy. No método proxy, ele determinará se existe um objeto que implementa a interface MethodInterceptor. Se existir, o método de interceptação será chamado para proxy o método delegado. Vantagens: ele pode aprimorar a operação da classe ou interface no tempo de execução, e a classe Delegate não precisa implementar a interface. Desvantagens: não pode procurar a classe final e o método final.
Resumir
O acima é o conteúdo inteiro deste artigo. Espero que o conteúdo deste artigo tenha certo valor de referência para o estudo ou trabalho de todos. Se você tiver alguma dúvida, pode deixar uma mensagem para se comunicar. Obrigado pelo seu apoio ao wulin.com.