La expresión de aspecto SpringAOP más completa

Artículos relacionados en el pasado :
conceptos básicos de AOP y aspectos de SpringAOP Introducción de
10 minutos a SpringAOP

prefacio

Que es PCD

PCD (designadores de corte de puntos) es la expresión de corte de puntos de SpringAOP. El PCD de SpringAOP es totalmente compatible con AspectJ, y hay 10 tipos en total.

PCD de un vistazo

imagen-20210108140219721

orientación del usuario

Spring AOP se implementa en base a un proxy dinámico, lo siguiente se usa para 目标对象representar el bean proxy y el objeto proxy representa el bean construido por AOP. El método de destino representa el método que se está transfiriendo.

ejecución

La ejecución es el PCD más utilizado. Su plantilla coincidente se muestra a continuación:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
          throws-pattern?)
execution(修饰符匹配式? 返回类型匹配式 类名匹配式? 方法名匹配式(参数匹配式) 异常匹配式?)

Las ?fórmulas de coincidencia firmadas en el bloque de código son todas opcionales y execution PCDsolo hay tres esenciales:

  1. Valor de retorno valor coincidente
  2. Coincidencia de nombre de método
  3. Coincidencia de parámetros

Análisis de ejemplo: execution(public * ServiceDemo.*(..))coincide con el modificador público, el valor de retorno es *, es decir , cualquier tipo de valor de retorno es correcto, ServiceDemoel tipo de coincidencia de nombre de clase no tiene que ser la ruta completa, siempre que la visibilidad global sea única , .*es el tipo de coincidencia de nombre de método, coincidente con todos los métodos, ..sí Tipo de coincidencia de parámetros, un método para hacer coincidir cualquier número y cualquier tipo de parámetro.

Dé algunos otros ejemplos:

  • execution(* com.xyz.service..*.*(..)): Haga coincidir cualquier método en com.xyz.service y sus subpaquetes.

  • execution(* joke(Object+))): Coincide con cualquier jokemétodo cuyo nombre sea , y su parámetro de entrada dinámica sea Tipo de objeto o una subclase de esta clase.

  • execution(* joke(String,..)): Haga coincidir jokeel método con cualquier nombre , un parámetro de entrada de este método es String (no puede ser una subclase), puede haber cualquier número de parámetros de entrada y el tipo de parámetro de entrada es ilimitado

  • execution(* com..*.*Dao.find*(..)): Coincide con el método al principio de buscar en el paquete especificado

  • execution(* com.baobaotao.Waiter+.*(..)): Coincide con Waitertodos los métodos del paquete com.baobaotao y sus subclases.

dentro

Filtre todas las clases de un determinado paquete y preste atención a ellas *.

  • within(com.xyz.service.*)Clases del paquete com.xyz.service, excluidos los subpaquetes

  • within(com.xyz.service..*)Clases del paquete com.xyz.service y sus subpaquetes

esta

Usado a menudo 命名绑定模式. Filtrar por tipo de objeto proxy.

Si la clase de destino se implementa en base a una interfaz, this()se puede completar el 该接口nombre de ruta completo. De lo contrario, debido a que la implementación sin interfaz se basa en CGLIB, 目标类el nombre de ruta completo se puede completar aquí .

this(com.xyz.service.AccountService): La clase de proxy es com.xyz.service.AccountService o sus subclases.

El uso @EnableAspectJAutoProxy(proxyTargetClass = true)puede forzar el uso de CGLIB. De lo contrario, el proxy dinámico jdk se usa primero por defecto, y CGLIB solo se usará si jdk no es un proxy.

objetivo

Esto actúa sobre el objeto proxy y el objetivo actúa sobre el objeto objetivo.

target(com.xyz.service.AccountService): La clase de proxy (objeto de destino) es com.xyz.service.AccountService o sus subclases

argumentos

A menudo se utiliza para hacer coincidir los parámetros del método de destino. Generalmente no se usa solo, sino que se usa junto con otros PCD. args puede usar 命名绑定modos, como se muestra a continuación:

@Aspect // 切面声明
@Component // 注入IOC
@Slf4j
class AspectDemo {
    
    
    @Around("within(per.aop.*) && args(str)") // 在per.aop包下,且被代理方法的只有一个参数,参数类型是String或者其子类
    @SneakyThrows
    public Object logAspect(ProceedingJoinPoint pjp, String str) {
    
     
        String signature = pjp.getSignature().toString();
        log.info("{} start,param={}", signature, pjp.getArgs());
        Object res = pjp.proceed();
        log.info("{} end", signature);
        return res;
    }
}
  1. Si la respuesta es sí en los argumentos, 参数名utilice el método de asesoramiento para determinar el tipo de parámetro del método que debe coincidir.
  2. Si args es un tipo, por ejemplo @Around("within(per.aop.*) && args(String)”), no necesita usar el método de aspecto para determinar el tipo, pero no puede usar el enlace de parámetros en este momento . Consulte a continuación .

Aunque se args()admiten +símbolos, esta provincia args()admite comodines de subcategoría.

executionDiferencia con la coincidencia de parámetros

Por ejemplo: args(com.xgj.Waiter)equivalente a execution(* *(com.xgj.Waiter+)). Y la ejecución no puede soportar consejos con parámetros.

@objetivo

Ejemplos de escenarios de uso: cuando un servicio tiene varias subclases, algunas subclases deben registrarse y algunas subclases no necesitan registrarse, lo que se puede manejar de la siguiente manera (con polimorfismo de Java):

Filtre si el objeto proxy con la anotación dada es un objeto o no una clase, y @target es dinámico . Personalice una anotación de la siguiente manera LogAble:

//全限定名: annotation.LogAble
@Target({
    
    ElementType.TYPE,ElementType.PARAMETER}) // 支持在方法参数、类上注
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAble {
    
    
}

Si necesita " publicregistrar los métodos de todas las clases con esta anotación ", entonces la lógica de registro debe personalizarse . Puede escribir PCD de la siguiente manera. Por supuesto, el bean de método correspondiente debe inyectarse en el contenedor SpringIOC:

@Around("@target(annotation.LogAble) && execution(public * *.*(..))")
// 自定义日志逻辑

@args

运行时类型Deben @argsespecificarse anotaciones para los parámetros del método de destino . Es el tipo de parámetro de método que tiene una anotación específica, no la anotación en el parámetro de método.

Escenario de uso: si el tipo de parámetro tiene varias subclases, solo una determinada subclase puede coincidir con el PCD.

  • @args(com.ms.aop.jargs.demo1.Anno1): Se requiere el parámetro Match 1 y la anotación Anno1 cuando se ejecuta el primer parámetro

  • @args(com.ms.aop.jargs.demo1.Anno1,..)Para hacer coincidir uno o más parámetros, el primer parámetro debe anotarse con Anno1 cuando se ejecuta.

  • @args(com.ms.aop.jargs.demo1.Anno1,com.ms.aop.jargs.demo1.Anno2): Un parámetro coincide con Anno1, dos parámetros coinciden con Annno2.

@dentro

No 运行时类型的de @target. @target se enfoca en el objeto que se llama y @within se enfoca en la clase donde se llama al método.

La diferencia entre @target y @within:

@target (Anotación A): determina 目标对象si la anotación A está declarada en la llamada , si la hay, será interceptada

@within (Anotación A): determina si la anotación A está declarada en el método al que pertenece el método llamado . Si lo hay, será interceptado

@anotación

Haga coincidir el método con la anotación especificada (la anotación actúa sobre el método)

frijol

Según beanNam para que coincida. Soporta *comodines.

bean(*Service) // 匹配所有Service结尾的Service

otro

Uso combinado

&& || !Se admiten tres tipos de operadores entre PCD . El operador && se utiliza en el ejemplo anterior. ||Significa o (sin cortocircuito o). !Representa no.

Modo de enlace con nombre

El @Around("within(per.aop.*) && args(str)")ejemplo anterior es utilizar el modo de vinculación con nombre, escribir el nombre de la variable en el PCD y limitar el tipo de nombre de la variable en el método.

@Around("within(per.aop.*) && args(str)")
public Object logAspect(ProceedingJoinPoint pjp, String str) {
    
     ...}

Como en el ejemplo anterior, si str es de tipo String o su subclase, y el método solo puede tener un parámetro.

el enlace de nombre solo se permite en los pcds de destino, esto y args

El modo de enlace mencionado solo admite target、this、argstres PCD.

argNames

Observando el código fuente, podemos encontrar que todas las anotaciones de Advice tienen argNamescampos, como @Around:

@Retention(RetentionPolicy.RUNTIME)
@Target({
    
    ElementType.METHOD})
public @interface Around {
    
    
    String value();
    String argNames() default "";
}

En qué circunstancias se utilizará este atributo, el siguiente ejemplo explica:

@Around(value = "execution(* TestBean.paramArgs(..))  && args(decimal,str,..)&& target(bean)", argNames = "pjp,str,decimal,bean")
@SneakyThrows // proceed会抛受检异常
Object aroundArgs(ProceedingJoinPoint pjp,/*使用命名绑定模式*/ String str, BigDecimal decimal, Object bean) {
    
    
    // 在方法执行前做一些操作
	return  pjp.proceed();
}

Los nombres de arg deben usarse con args, target, this tags. Aunque no es necesario en funcionamiento real, la recomendación oficial es traer todos los parámetros con parámetros por las siguientes razones:

Por lo tanto, si no se especifica el atributo 'nombres de archivo', Spring AOP observará la información de depuración de la clase e intentará determinar el nombre del parámetro a partir de la tabla de variables locales. Este mensaje aparecerá siempre que la clase se compile con información de depuración (al menos '-g: vars'). El resultado de compilar con esta bandera es:

(1) Su código será más fácil de realizar ingeniería inversa)

(2) El tamaño del archivo de la clase será muy grande (generalmente irrelevante)

(3) El compilador no aplicará la optimización de la eliminación de variables locales no utilizadas.

Además, si el código compilado no tiene la información de depuración necesaria, Spring AOP intentará inferir el emparejamiento de variables de enlace y parámetros. Si el enlace de la variable es ambiguo bajo la información disponible, se lanzará una AmbiguousBindingException. Si las estrategias anteriores fallan, se lanzará una IllegalArgumentException.

Se recomienda incluir todos los comentarios de consejos, argNamesy la idea se lo recordará de todos modos.

Articulo de referencia

  1. Documentación de primavera
  2. Expresión de punto SpringAOP

Supongo que te gusta

Origin blog.csdn.net/qq_38619183/article/details/112359456
Recomendado
Clasificación