Cómo obtener la clase de proxy del proxy dinámico de Java
Entonces, ¿cómo entrelaza el proxy dinámico la lógica de conmutación (sugerencia) en el método de la clase objetivo? A continuación, presentaremos e implementaremos en detalle los dos servidores proxy dinámicos utilizados en AOP.
El código fuente de AOP utiliza dos servidores proxy dinámicos para implementar la función de intercepción y corte: proxy dinámico jdk y proxy dinámico cglib. Ambos métodos existen simultáneamente, cada uno con sus pros y sus contras. El proxy dinámico jdk se implementa mediante el mecanismo de reflexión interno de Java, mientras que el proxy dinámico cglib se implementa mediante asm en el nivel inferior. En términos generales, el mecanismo de reflexión es más eficiente en el proceso de generación de clases, mientras que asm es más eficiente en el proceso de ejecución relacionado después de generar la clase (las clases se pueden generar a través del caché de clases asm, lo que resuelve el problema de la baja eficiencia en el pregunta sobre el proceso de generación de clases asm). Otro punto a tener en cuenta es que el requisito previo para una aplicación de proxy dinámico jdk debe ser que la clase de destino se base en una interfaz unificada. Sin tal premisa, no se puede aplicar el proxy dinámico jdk. Se puede ver que el proxy dinámico jdk tiene ciertas limitaciones. Los proxy dinámicos implementados por bibliotecas de terceros como cglib se utilizan más ampliamente y tienen más ventajas en términos de eficiencia.
1. Definir la interfaz y la implementación
[java] ¿Ver impresión de copia pura?
paquete com.meituan.hyt.test3.service
interfaz pública UserService {
cadena pública getName(int id);
entero público getAge(int id);
[java] ¿Ver impresión de copia pura?
[java] ¿Ver impresión de texto puro?
paquete com.meituan.hyt.test3.service.impl;
importar com.meituan.hyt.test3.service.UserService
clase pública UserServiceImpl; implementa UserService {
@Override
public String getName(int id) {
System.out.println("------getName-- ----");
return "Tom";
}
@Override
entero público getAge(int id) {
System.out.println("------getAge------");
return 10; /p>
}
2. Implementación de proxy dinámico jdk
[java] ¿Ver impresión de copia pura?
MyInvocationHandler() {
super();
}
MyInvocationHandler(Objeto objetivo) {
super();
this.target = target;
}
@Override
invocación de objeto público (Objeto o, método , Object[] args) throws Throwable {
if("getName".equals(method.getName())){
System.out.println(" before " método. getName() " ");
Resultado del objeto = método.invoke(destino, argumentos
Resultado del objeto = método.invoke(destino, argumentos
<); p>Resultado del objeto = método.invoke(destino, argumentos);Resultado del objeto = método.invoke(destino, argumentos)invocar(destino, argumentos);
System.out. println(" después de " método.getName()
" ");
resultado de retorno;
}else{
Resultado del objeto = método.invoke(destino, argumentos); devolver resultado;
}
}
}
}
[java] ¿Ver impresión de texto sin formato?
paquete com.meituan.hyt.test3.jdk;
importar com.meituan.hyt.test3.service.UserService
importar com.meituan. hyt.test3.
clase pública Main1 {
public static void main(String[] args) {
UserService userService = new UserServiceImpl(); p>
p>
InvocationHandler invocationHandler = new MyInvocationHandler(userService);
UserService userServiceProxy = (UserService)Proxy.newProxyInstance( userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(), invocationHandler);
System.out.println (userServiceProxy.getName(1)); userServiceProxy.getAge(1) ));
}
}
Ejecución de resultados
antes de getName
------ getName------
después de getName
Tom
------getAge------
10
3.cglib implementación de proxy dinámico
Cglib es un excelente marco de proxy dinámico. Su capa inferior utiliza ASM para generar dinámicamente subclases de la clase de proxy. memoria Incluso si usa CGLIB La clase de proxy puede implementar la función de proxy dinámico sin implementar ninguna interfaz. cglib.proxy.MethodProxy: la clase proxy de la clase java.lang.reflect.Method de JDK, que puede llamar fácilmente al método del objeto fuente, por ejemplo, use:
Objeto o = métodoProxy.invokeSuper(proxy , args); // Aunque el primer parámetro es el objeto proxy, no hay un bucle infinito.
La interfaz net.sf.cglib.proxy.MethodInterceptor es el tipo de devolución de llamada más común y es comúnmente utilizada por AOP basado en proxy para implementar la interceptación de llamadas a métodos.
Esta interfaz solo define un método
intercepción de objeto público (objeto objeto, método java.lang.reflect.Method,
argumentos de objeto [], proxy MethodProxy) throws Throwable;
p>El primer parámetro es el par de proxy, y el segundo y tercer parámetro son el método interceptado y los parámetros del método respectivamente. El método original se puede llamar mediante reflexión normal utilizando el objeto java.lang.reflect.Method o utilizando el objeto net.sf.cglib.proxy.MethodProxy. net.sf.cglib.proxy.MethodProxy es generalmente preferible porque es más rápido.
[java] ¿Ver impresión de texto sin formato?
paquete com.meituan.hyt.test3.cglib;
importar net.sf.cglib.proxy.MethodInterceptor
importar net.sf.cglib. proxy.MethodProxy;
import java.lang.reflect.MethodInterceptor {
[java] Ver impresión de texto sin formato.
MethodInterceptor {
@Override
interceptación de objeto público (Objeto o, método de método, argumentos de objeto[], MethodProxy métodoProxy) throws Throwable {
System.out. println(" antes de " métodoProxy.getSuperName() " ");
System.out.println(method.getName()
Objeto o1 = métodoProxy.invokeSuper(o, args);
System.out.println(" antes de " métodoProxy.getSuperName() " ");
return o1;
}
[java] ¿Ver impresión de texto sin formato?
paquete com.meituan.hyt.test3.cglib;
importar com.meituan.Enhancer
clase pública Main2 {
public static void main(String[] args) {
CglibProxy cglibProxy = nuevo CglibProxy();
Mejorador potenciador = nuevo potenciador
mejorador. setSuperclass(UserServiceImpl.class);
enhancer.setCallback(cglibProxy);
UserService o = (UserService)enhancer.create();
o.getName; (1);
o.getAge(1);
}
}
}
Ejecución resultado:
antes CGLIB$getName$0
getName
------getName------
antes CGLIB$getName$0
antes de CGLIB$getAge$1
getAge
------getAge------
antes de CGLIB$getAge$1