introducir
Como todos sabemos, AOP (programación orientada a la sección) es una de las características de Spring Frameworks. AOP proporciona una escalabilidad extremadamente alta al establecer preocupaciones de corte cruzado. Entonces, ¿cómo funciona AOP en primavera? Cuando solo puede usar Java Core pero necesita tecnología AOP, la respuesta a esta pregunta se vuelve extremadamente crítica. No solo eso, en entrevistas para puestos técnicos avanzados, tales preguntas a menudo aparecen como preguntas de prueba. Mire, mi amigo asistió recientemente a una entrevista y se le hizo una pregunta tan difícil: cómo implementar AOP sin usar bibliotecas de primavera y relacionadas, y solo Java central. Por lo tanto, proporcionaré un esquema en este artículo para ayudarlo a comprender cómo implementar un AOP usando Java central (por supuesto, esto tiene ciertas limitaciones funcionales). Tenga en cuenta que este artículo no es un estudio comparativo de Spring AOP y Java AOP, sino un tutorial sobre la implementación de AOP con la ayuda de patrones de diseño inherentes en Java central.
Creo que los lectores ya saben qué es AOP y cómo usarlo en el marco de Spring, por lo que este artículo solo se centra en cómo implementar AOP sin usar Spring. En primer lugar, debemos saber que Spring usa dos tecnologías: JDK Proxy y CGLIB para implementar AOP. JDK Dynamic Proxy proporciona una forma flexible de enganchar un método y realizar operaciones especificadas, pero debe haber una restricción al realizar operaciones: una interfaz relacionada y la clase de implementación de la interfaz se deben proporcionar primero. ¡Practique para crear un verdadero conocimiento, comprendamos esta oración a través de un caso! Ahora hay un programa de calculadora para hacer algunas operaciones matemáticas. Consideremos la función de división. La pregunta en este momento es: si el marco principal ya tiene un código para implementar la división, ¿podemos secuestrarla y realizar una verificación adicional cuando se ejecuta el código? La respuesta es sí, y lo demostraré con el fragmento de código que se proporciona a continuación. Primero, veamos el código de la interfaz básica:
Calculadora de interfaz pública {public int calculate (int a, int b);}El código de esta clase de implementación de la interfaz es el siguiente:
Public Class CalculatorImpl implementa la calculadora {@Override public int calculación (int a, int b) {return a/b; }}Suponiendo que no podemos reparar el código anterior o hacer ningún cambio en la biblioteca central, ¿cómo podemos implementar perfectamente la función de verificación? ¿Por qué no probar la función proxy dinámica JDK?
clase pública SomeHandler implementa InvocationHandler {// Código omitido por simplicidad ... .. @Override Public Object Invoke (Object Proxy, Method Method, Object [] Params) lanza Throwable {// Su compleja validación comercial y resultado de objeto lógico = Method.invoke (TargetObject, Params); resultado de retorno; }}Veamos cómo funciona la función de verificación implementada por JDK Dynamic Proxy a través de la clase de prueba.
public static void main (string [] args) {calculatorImpl calcImpl = new calculatulatulImpl (); Calculadora proxied = (calculadora) proxyfactory.getProxy (calculator.class, calcimppl, new SomeHandler (CalcImpl)); int resultado = proxied.calculate (20, 10); System.out.println ("Resultado final :::" + resultado); }De los resultados, podemos ver que simplemente implementando la poderosa interfaz InvocationHandler, podemos obtener una implementación de enganche. Según la documentación JDK, la interfaz InvocationHandler utiliza una instancia de proxy para manejar una llamada de método.
Ahora sabemos que el método Invoke () de InvocationHandler puede ayudarnos a resolver el problema. Entonces, resolvamos un nuevo problema: ¿cómo podemos realizar operaciones antes y después de la ejecución del método? Para decirlo más específicamente, ¿podemos enganchar un método agregando múltiples AOP (antes, después, alrededor) (Nota del traductor: el texto original es agregar múltiples AOP, pero creo que Handler actúa como un aspecto)? La respuesta también es sí. Siga los pasos a continuación para crear una plantilla de código simplificada para cumplir con este requisito:
Dos formas de implementar AOP:
1. Implementación de proxy dinámico proporcionada por JDK
interfaz
interfaz pública userbean {void getUSer (); Adduser void (); Void UpdateUser (); nulo deleteUser (); } Clase de implementación original
Public Class UserBeanImpl implementa UserBean {private String user = null; public userBeanImpl () {} public userBeanImpl (String user) {this.user = user; } public String getUsername () {return user; } public void getUSer () {System.out.println ("¡Este es el método getUser ()!"); } public void setUser (user de cadena) {this.user = user; System.out.println ("Este es el método setUser ()!"); } public void addUser () {System.out.println ("Este es el método adduser ()!"); } public void UpdateUser () {System.out.println ("Este es el método updateUser ()!"); } public void DeleteUser () {System.out.println ("Este es el método deleteuser ()!"); }} Clase de agente
import java.lang.reflect.invocationHandler; import java.lang.reflect.method; import java.lang.reflect.proxy; import com.cignacmc.finance.bean.userbeanimpl; UserBeanProxy de clase pública implementa InvocationHandler {private Object TargetObject; Public UserBeanProxy (Object TargetObject) {this.TargetObject = TargetObject; } Public Object Invoke (Object proxy, método método, objeto [] args) lanza lando {userBeanImpl userBean = (userBeanImpl) TargetObject; String UserName = UserBean.GetUsername (); Resultado del objeto = nulo; // juicio de permiso if (username! = Null &&! "". Equals (UserName)) {result = Method.Invoke (TargetObject, args); } resultado de retorno; }}
Clase de prueba
import java.lang.reflect.proxy; import com.cignacmc.finance.bean.userbean; import com.cignacmc.finance.bean.userbeanimpl; import com.cignacmc.finance.proxy.userbeanproxy; public class proxyExe {public static void main (string [] args) {system.out.println ("probado ........."); UserBeanImpl TargetObject = new UserBeanImpl ("Bob Liang"); UserBeanProxy proxy = new UserBeanProxy (TargetObject); // Generar objeto proxy userBean Object = (userBean) proxy.newproxyInstance (TargetObject.getClass (). GetClassLoader (), TargetObject.getClass (). GetInterfaces (), proxy); objeto.adduser (); System.out.println ("No probado ............"); TargetObject = new UserBeanImpl (); proxy = new UserBeanProxy (TargetObject); // Generar proxy objeto objeto = (userbean) proxy.newproxyInstance (TargetObject.getClass (). GetClassLoader (), TargetObject.getClass (). GetInterfaces (), proxy); objeto.adduser (); }}
Producción:
Probado ............ ¡Este es el método aduser ()! No se probó ..........
Del ejemplo anterior, el método llamado Adduser () puede interceptarse y procesarse con éxito en consecuencia.
2. Crear clase proxy a través de CGLIB
La ventaja es que nuestro objeto objetivo no requiere que la clase primitiva de interfaz se implemente.
clase pública clientBean {private string name = null; public ClientBean () {} public ClientBean (nombre de cadena) {this.name = name; } public void addClient () {System.out.println ("Este es el método adCclient ()!"); } public void DeleteClient () {System.out.println ("Este es el método deleteclient ()!"); } public void getClient () {System.out.println ("Este es el método getClient ()!"); } public void getClient () {System.out.println ("Esto es método getClient ())!"); } public void updateClient () {System.out.println ("Este es el método updateClient ()!"); } public String getClientName () {nombre de retorno; } public void setClientName (nombre de cadena) {this.name = name; }} Clase de agente
import java.lang.reflect.method; import com.cignacmc.finance.bean.clientbean; importar net.sf.cglib.proxy.enhancer; importar net.sf.cglib.proxy.methodinterceptor; importar net.sf.cglib.proxy.methodinterceptor; importar net.sf.cglib.proxy.methodproxy; clase pública cglibproxy implementa métodosinterceptor {private object TargetObject; objeto público createProxyObject (objeto TargetObject) {this.targetObject = TargetObject; Potencador potencador = nuevo mejor (); potencer.setsuperClass (this.targetObject.getClass ()); potencador.setCallback (esto); return mejor.create (); } Public Object Intercept (proxy de objeto, método método, objeto [] args, métodeProxy MethodProxy) lanza lando {ClientBean ClientBean = (ClientBean) TargetObject; String UserName = ClientBean.getClientName (); Resultado del objeto = nulo; if (username! = null &&! "". Equals (UserName)) {result = Method.Invoke (TargetObject, args); } resultado de retorno; }} Clase de prueba
import java.lang.reflect.proxy; import com.cignacmc.finance.bean.clientbean; import com.cignacmc.finance.bean.userbean; import com.cignacmc.finance.bean.userbeanimpl; import com.cignacmc.finance.proxy.cglibproxy; import com.cignacmc.finance.proxy.userbeanproxy; public class proxyExe {public static void main (string [] args) {System.out.println ("........ cglib proxy ............"); System.out.println ("probado ..............."); Cglibproxy cproxy = new cglibproxy (); ClientBean ClientBean = (ClientBean) Cproxy.CreateProxyObject (new ClientBean ("Bob Liang")); ClientBean.AddClient (); System.out.println ("No probado ..............."); cproxy = new cglibproxy (); ClientBean = (ClientBean) Cproxy.CreateProxyObject (new ClientBean ()); ClientBean.AddClient (); }}
Producción:
..... cglib proxy .................. probado ............ ¡Este es el método adclient ()! No se probó ............