El análisis del modo proxy, el proxy estático y el proxy dinámico te lo dirán todo

Patrón de proxy

Después de dos meses de aprendizaje, nuestra serie de patrones de diseño está llegando a su fin. Sin embargo, los patrones de diseño definitivamente no se dominarán por un tiempo, y debemos continuar practicando en el trabajo de seguimiento. Con este tipo de pensamiento, el resto es entrenamiento deliberado por su cuenta.

Lo que trajimos hoy es el patrón de proxy, Proxy Pattern. Este modo debe ser familiar para todos, porque Spring Aop, al que generalmente preguntan los programadores de Java en las entrevistas, hablará sobre el proxy dinámico, que en realidad es una implementación del modo proxy. Sin embargo, es posible que la mayoría de la gente no lo haya entendido de manera sistemática. El propósito de este artículo es comprender a fondo el pequeño 99 del modelo de agencia.

Antes de leer, también pienso en algunas preguntas sobre el modelo de agencia, y aprendo con el propósito de aclarar el problema.

Empiece con preguntas

  1. ¿Qué es el modelo de agencia?
  2. Proxy estático?
  3. Proxy dinámico?
  4. ¿Variantes comunes del modelo de proxy?

Introducción al modo proxy

Modo proxy: proporciona un marcador de posición o sustituto para un objeto para controlar el acceso a este objeto. Es decir, se accede al objeto de destino a través del objeto proxy. La ventaja de esto es que puede mejorar las operaciones funcionales adicionales basadas en la realización del objeto de destino, es decir, ampliar la función del objeto de destino. Pero el enfoque aquí todavía está en el control del acceso al "objeto".

  1. Los objetos proxy pueden ser: objetos remotos, objetos que son costosos de crear u objetos que requieren control de seguridad;
  2. El modo proxy tiene diferentes formas, hay tres tipos principales: proxy estático, proxy dinámico (JDK y Cglib);

Diagrama de clases del modelo de agente

Inserte la descripción de la imagen aquí

Proxy estático

Cuando se utiliza un proxy estático, es necesario definir una interfaz o una clase principal. El objeto proxy (objeto de destino) y el objeto proxy implementan la misma interfaz o heredan la misma clase principal.

Aplicaciones

Requisitos específicos

  1. Definir una interfaz: ITeacherDao
  2. El objeto actual TeacherDAO implementa ITeacherDao
  3. Para usar un proxy estático, debe implementar la interfaz ITeacherDao en TeacherDAOProxy
  4. Al llamar, llame al objeto de destino llamando al método del objeto proxy
  5. Atención especial: el objeto proxy debe implementar la misma interfaz que el objeto de destino y luego llamar al método del objeto de destino llamando al mismo método

Diagrama de análisis de ideas (diagrama de clases)

Inserte la descripción de la imagen aquí

Código

public class Client {
    
    

	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		//创建目标对象(被代理对象)
		TeacherDao teacherDao = new TeacherDao();
		
		//创建代理对象, 同时将被代理对象传递给代理对象
		TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
		
		//通过代理对象,调用到被代理对象的方法
		//即:执行的是代理对象的方法,代理对象再去调用目标对象的方法 
		teacherDaoProxy.teach();
	}

}
//接口
public interface ITeacherDao {
    
    
	
	void teach(); // 授课的方法
}
public class TeacherDao implements ITeacherDao {
    
    

	@Override
	public void teach() {
    
    
		// TODO Auto-generated method stub
		System.out.println(" 老师授课中  。。。。。");
	}

}
//代理对象,静态代理
public class TeacherDaoProxy implements ITeacherDao{
    
    
	
	private ITeacherDao target; // 目标对象,通过接口来聚合
	
	//构造器
	public TeacherDaoProxy(ITeacherDao target) {
    
    
		this.target = target;
	}

	@Override
	public void teach() {
    
    
		// TODO Auto-generated method stub
		System.out.println("开始代理  完成某些操作。。。。。 ");//方法
		target.teach();
		System.out.println("提交。。。。。");//方法
	}

}

Ventajas y desventajas del proxy estático

  1. Ventajas: la función de destino se puede ampliar a través del objeto proxy sin cambiar la función del objeto de destino
  2. Desventajas: obviamente, debido a que el objeto proxy necesita implementar la misma interfaz que el objeto de destino, habrá muchas clases de proxy
  3. Una vez que se agrega un método a la interfaz, el objeto de destino y el objeto de proxy deben mantenerse

Proxy dinámico

El agente dinámico se divide en agente dinámico JDK y agente dinámico Cglib. Veamos cómo funciona el agente dinámico JDK.

Proxy dinámico JDK

  1. El objeto proxy no necesita implementar la interfaz, pero el objeto de destino debe implementar la interfaz; de lo contrario, no se puede utilizar el proxy dinámico JDK
  2. La generación de objetos proxy utiliza la API de JDK para construir dinámicamente objetos proxy en la memoria.

API para generar objetos proxy en JDK

  1. El paquete donde se encuentra la clase de proxy:java.lang.reflect.Proxy
  2. El agente de implementación de JDK solo necesita usar el newProxyInstancemétodo, pero este método requiere tres parámetros, la redacción completa es:static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

Ejemplo de aplicación de proxy dinámico JDK

Aquí mejoraremos el ejemplo anterior usando proxy dinámico JDK a proxy dinámico.

Diagrama de ideas (diagrama de clases)

Inserte la descripción de la imagen aquí

Código

public class Client {
    
    

	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		//创建目标对象
		ITeacherDao target = new TeacherDao();
		
		//给目标对象,创建代理对象, 可以转成 ITeacherDao
		ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
	
		// proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
		System.out.println("proxyInstance=" + proxyInstance.getClass());
		
		//通过代理对象,调用目标对象的方法
		//proxyInstance.teach();
		
		proxyInstance.sayHello(" tom ");
	}

}
//接口
public interface ITeacherDao {
    
    

	void teach(); // 授课方法
	void sayHello(String name);
}
public class ProxyFactory {
    
    

	//维护一个目标对象 , Object
	private Object target;

	//构造器 , 对target 进行初始化
	public ProxyFactory(Object target) {
    
    
		
		this.target = target;
	} 
	
	//给目标对象 生成一个代理对象
	public Object getProxyInstance() {
    
    
		
		//说明
		/*
		 *  public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
                                          
            //1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
            //2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
            //3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
		 */
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
				target.getClass().getInterfaces(), 
				new InvocationHandler() {
    
    
					
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
						// TODO Auto-generated method stub
						System.out.println("JDK代理开始~~");
						//反射机制调用目标对象的方法
						Object returnVal = method.invoke(target, args);
						System.out.println("JDK代理提交");
						return returnVal;
					}
				}); 
	}
	
}
public class TeacherDao implements ITeacherDao {
    
    

	@Override
	public void teach() {
    
    
		// TODO Auto-generated method stub
		System.out.println(" 老师授课中.... ");
	}

	@Override
	public void sayHello(String name) {
    
    
		// TODO Auto-generated method stub
		System.out.println("hello " + name);
	}
	
}

El código también es muy simple, si no está familiarizado con él, asegúrese de escribir el código de arriba para tener una idea.

Proxy dinámico cglib

  1. Tanto el proxy estático como el proxy dinámico JDK requieren que el objeto de destino implemente una interfaz, pero a veces el objeto de destino es solo un objeto único y no implementa ninguna interfaz. En este caso, puede usar una subclase del objeto de destino para implementar el proxy, que es el proxy Cglib.

  2. El agente Cglib también se denomina agente de subclase, que consiste en expandir el objeto de destino construyendo un objeto de subclase en la memoria.

  3. Cglib es un potente paquete de generación de código de alto rendimiento que puede extender clases Java e implementar interfaces Java en tiempo de ejecución. Es ampliamente utilizado por muchos frameworks AOP, como Spring AOP, para implementar la interceptación de métodos.

  4. ¿Cómo elegir qué proxy dinámico usar en la programación AOP?

    1. El objeto de destino implementa la interfaz y usa el proxy dinámico JDK
    2. El objeto de destino no necesita implementar la interfaz, use Cglib para implementar el proxy
  5. La capa inferior del paquete Cglib es el marco de procesamiento de código de bytes ASM para convertir bytes y generar nuevas clases

Pasos de implementación del proxy dinámico de cglib

  1. Necesito presentar el paquete jar de cglib

  2. Las subclases se crean dinámicamente en la memoria, por lo que la clase (objeto de destino) que necesita ser proxy no puede ser final; de lo contrario, se informará un error:
    Inserte la descripción de la imagen aquí

  3. Si el método del objeto proxy es final / estático, entonces el método de destino no se interceptará y no se realizará el procesamiento comercial adicional del método del objeto de destino, porque los métodos modificados final y estático no se pueden extender por subclases

Ejemplo de aplicación

Requisitos: implementar el ejemplo anterior usando el modo proxy Cglib

Diagrama de ideas (diagrama de clases)

Inserte la descripción de la imagen aquí

Código

public class Client {
    
    

	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		//创建目标对象
		TeacherDao target = new TeacherDao();
		//获取到代理对象,并且将目标对象传递给代理对象
		TeacherDao proxyInstance = (TeacherDao)new ProxyFactory(target).getProxyInstance();

		//执行代理对象的方法,触发intecept 方法,从而实现 对目标对象的调用
		String res = proxyInstance.teach();
		System.out.println("res=" + res);
	}

}
public class ProxyFactory implements MethodInterceptor {
    
    

	//维护一个目标对象
	private Object target;
	
	//构造器,传入一个被代理的对象
	public ProxyFactory(Object target) {
    
    
		this.target = target;
	}

	//返回一个代理对象:  是 target 对象的代理对象
	public Object getProxyInstance() {
    
    
		//1. 创建一个工具类
		Enhancer enhancer = new Enhancer();
		//2. 设置父类
		enhancer.setSuperclass(target.getClass());
		//3. 设置回调函数
		enhancer.setCallback(this);
		//4. 创建子类对象,即代理对象
		return enhancer.create();
		
	}

	//重写  intercept 方法,会调用目标对象的方法
	@Override
	public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
    
    
		// TODO Auto-generated method stub
		System.out.println("Cglib代理模式 ~~ 开始");
		Object returnVal = method.invoke(target, args);
		System.out.println("Cglib代理模式 ~~ 提交");
		return returnVal;
	}

}
public class TeacherDao {
    
    

	public String teach() {
    
    
		System.out.println(" 老师授课中  , 我是cglib代理,不需要实现接口 ");
		return "hello";
	}
}

Variaciones de varios modos de proxy comunes

  1. Proxy de firewall

    1. La red interna realiza la penetración del firewall a través del proxy y realiza el acceso a la red pública.
  2. Proxy de caché

    1. Cuando solicite archivos como imágenes, primero vaya al agente de caché para buscarlos, si puede obtener los recursos, todos están contentos, si no puede obtenerlos, vaya a la red pública o la base de datos para buscarlos y luego almacene en caché
  3. Agente remoto

    1. El proxy local del objeto remoto, a través del cual se puede llamar al objeto remoto como el objeto local. El objeto proxy remoto se comunica con el objeto remoto real a través del protocolo de red.

para resumir

Este artículo utiliza diagramas de clases y ejemplos de código para brindar una explicación detallada del modelo de proxy, con el objetivo de permitirle comprender la definición del modelo de proxy y el proxy estático, el proxy proxy y la diferencia entre el proxy dinámico JDK y el proxy dinámico Cglib y la implementación. la manera.

El autor pasa localmente el código de texto completo y se puede utilizar directamente para realizar pruebas.


¡Se acabó el texto completo, luchando!

Cuenta pública personal

Inserte la descripción de la imagen aquí

  • Los amigos que sienten que están escribiendo bien pueden molestarse en dar me gusta y seguir ;
  • Si el artículo es incorrecto, indíquelo, muchas gracias por leerlo;
  • Recomiendo a todos que presten atención a mi cuenta oficial, y regularmente les enviaré artículos originales de productos secos y los llevaré a la comunidad de aprendizaje de alta calidad;
  • dirección de github : github.com/coderluojust/qige_blogs

Supongo que te gusta

Origin blog.csdn.net/taurus_7c/article/details/107890887
Recomendado
Clasificación