The AspectJ Pointcut syntax is very detailed
Classified pointcuts follow a specific syntax to capture the usable join points of each kind. Main types:
Method execution: execution(MethodSignature)
Method call: call(MethodSignature)
Constructor execution: execution(ConstructorSignature)
Constructor call: call(ConstructorSignature)
Class initialization: staticinitialization(TypeSignature)
Property read operation: get(FieldSignature)
Attribute write operation: set(FieldSignature)
Exception handling execution: handler(TypeSignature)
Object initialization: initialization(ConstructorSignature)
Object pre initialization: preinitialization(ConstructorSignature)
Advice execution: adviceexecution()
The pointcut indicator is used to indicate the purpose of the pointcut expression. At present, there is only one connection point, the execution method, in Spring AOP. The AspectJ pointcut indicators supported by Spring AOP are as follows:
Execution: the connection point used to match the execution of the method;
Within: used to match the method execution within the specified type;
this: the execution method used to match the current AOP proxy object type; Note the type matching of AOP proxy object, which may include the introduction of interface type matching;
Target: the execution method used to match the current target object type; Note that the type matching of the target object does not include the type matching of the imported interface;
args: used to match the currently executed method. The parameter passed in is the execution method of the specified type;
@Within: used to match the methods within the specified annotation type;
@Target: the execution method used to match the current target object type, where the target object holds the specified annotation;
@args: used to match the execution of the currently executed method. The parameters passed in hold the specified annotation;
@Annotation: used to match the method with the specified annotation held by the current execution method;
Bean: extended by Spring AOP, AspectJ has no execution method for the indicator to match the bean object with a specific name;
reference pointcut: refers to referencing other named pointcuts. Only @ ApectJ style is supported, but Schema style is not.
To learn about the following wildcards for AspectJ type matching:
: matches any number of characters;
...: matches the repetition of any number of characters, such as matching any number of subpackages in the type pattern; Match any number of parameters in the method parameter pattern.
+: matches the subtype of the specified type; Can only be placed after the type mode as a suffix.
java.lang.String matches the String type;
java..String matches the string type under any "first level sub package" under the java package;
Such as matching Java Lang. string, but does not match Java lang.ss. String
Java... * matches any type under java package and any sub package;
Such as matching Java lang.String,java.lang.annotation.Annotation
java.lang.*ing matches any Java Type ending in ing under Lang package;
java.lang.Number + matches Java Self type of any Number under Lang package;
Such as matching Java Lang. integer, which also matches Java math. BigInteger
For example:
Execution of any public method:
execution(public * (...))
Execution of any method starting with "set":
execution( set*(...))
Execution of any method of AccountService interface:
execution(* com.xyz.service.AccountService.(...))
Execution of any method defined in the service package:
execution( com.xyz.service..(...))
Execution of any method of any class defined in the service package and all sub packages:
execution(* com.xyz.service....(...))
Execution of any method of JoinPointObjP2 class defined in pointcutexp package and all sub packages:
execution(* com.test.spring.aop.pointcutexp...JoinPointObjP2.*(...))")
*>The closest (...) is the method name (...)) is the class name or interface name, such as JoinPointObjP2 (…))
Any class in the pointcutexp package
within(com.test.spring.aop.pointcutexp.)
pointcutexp package and any class in all sub packages
within(com.test.spring.aop.pointcutexp...)
Implements all classes of Intf interface. If Intf is not an interface, limit a single Intf class
this(com.test.spring.aop.pointcutexp.Intf)
***>When a class that implements an interface is AOP, the getBean method must cast as the interface type, not the type of this class
Any method of all classes with @ Transactional annotation
@within(org.springframework.transaction.annotation.Transactional)
@target(org.springframework.transaction.annotation.Transactional)
Any method with @ Transactional annotation
@annotation(org.springframework.transaction.annotation.Transactional)
***>@ within and @ target are annotations for classes, @ annotation is annotations for methods
Method with @ Transactional annotation for parameter
@args(org.springframework.transaction.annotation.Transactional)
The parameter is a method of String type (run is determined)
//@ Aspect can no longer decorate interfaces, but can only be classes
//aspectOf() and hasAspect() can no longer be used when accessing an aspect instance
//Instead, take the class of aspect as the parameter, and use org aspectj. Lang. aspects provides static methods aspectOf() and hasAspect()
@Aspect("perthis|pertarget|percflow|percflowbelow(Pointcut) | pertypewithin(TypePattern)")
//Defining the priority of aspect s requires the use of fully qualified names, which is very common in @ AspectJ and is also determined by the Java compiler
//Future versions of AspectJ may provide support for parameters of type string []
@DeclarePrecedence("ajia.HomeSecurityAspect, ajia.SaveEnergyAspect")
public abstract static class AspectName
extends class_or_aspect_name
implements interface_list
{
//Use @ pointcut with a placeholder method declaration to define a pointcut
//The abstract pointcut still has only names and parameters, and there is no actual joinpoint definition
@Pointcut
public abstract void pointcut_name(Type args);
// When defining pointcut, you should still pay attention to the use of fully qualified names // The method is just a placeholder, and the method body is empty except that it adopts the if() cut in method similar to conditional compilation // If the method throws an exception, you should also add the throws declaration to the method prototype // Remember to turn on the compiler option - g:vars and let the compiler reserve parameter names (this method is adopted for construction) @Pointcut("execution(public * ajia.banking.domain.Account.*(float)) && this(account) && args(amount)") public void accountOperation(Account account, float amount) {} // Or use the attribute of Annotation to establish the association between parameter name and pointcut // However, you have to maintain the consistency between argNames and the method parameter table, so it is not recommended @Pointcut(value="execution(public * ajia.banking.domain.Account.*(float)) && this(account) && args(amount)", argNames="account, amount") public void accountOperation(Account account, float amount) {} // The definition of advice is similar to the traditional syntax, // Before advice must be a combination of public and void // Method 1: anonymous pointcut @Before("execution(* *(..)) && !within(ajia.monitoring.*)") public void beatHeart() { heartBeatListener.beat(); } // Method 2: named pointcut @Pointcut("execution(* *.*(..)) && !within(ajia.monitoring.*)") public void aliveOperation() {} @Before("aliveOperation()") public void beatHeart() { heartBeatListener.beat(); } // advice still supports getting context via reflection of JoinPoint class // The JoinPoint object itself defines the dynamic part // JoinPoint.StaticPart defines the static part // JoinPoint.EnclosingStaticpart defines the part of the package static information // Meanwhile, advice still supports target/this/args @Pointcut("call(void Account.credit(float)) && target(account) && args(amount)") public void creditOperation(Account account, float amount) {} @Before("creditOperation(account, amount)" ) public void beforeCreditOperation(JoinPoint.StaticPart jpsp, JoinPoint.EnclosingStaticPart jpesp, Account account, float amount) { System.out.println("Crediting " + amount + " to " + account); } // The implementation of after advice is also intuitive @Pointcut("call(* java.sql.Connection.*(..)) && target(connection)") public void connectionOperation(Connection connection) {} @After("connectionOperation(connection)") public void monitorUse(Connection connection) { System.out.println("Just used " + connection); } @AfterReturning(value="connectionOperation(connection)", returning="ret") public void monitorSuccessfulUse(Connection connection, Object ret) { System.out.println("Just used " + connection + " successfully which returned " + ret); } @AfterThrowing(value="connectionOperation(connection)", throwing="ex") public void monitorFailedUse(Connection connection, Exception ex) { System.out.println("Just used " + connection + " but met with a failure of kind " + ex); } // The implementation of around advice is slightly complicated // You need to refer to the JoinPoint reflection method and pass in a ProceedingJoinPoint parameter for the around advice method // The object has the method proceed() and its overloaded version proceed(Object []), which can execute the cut in method // In this Object [] array, it is this target args in turn // It is obtained through the methods this(), target() and getArgs() of the ProceedingJoinPoint object @Around("pointcut_xxx()") public Object measureTime(ProceedingJoinPoint pjp) { Object[] context = formProceedArguments(pjp.this(), pjp.target(), pjp.getArgs()); Object result = proceed(context); return result; } // You can use the following method to get the Object [] array public static Object[] formProceedArguments(Object thiz, Object target, Object[] arguments) { int argumentsOffset = 0; if(thiz != null) { argumentsOffset++; } if(target != null) { argumentsOffset++; } Object[] jpContext = new Object[arguments.length + argumentsOffset]; int currentIndex = 0; if(thiz != null) { jpContext[currentIndex++] = thiz; } if(target != null) { jpContext[currentIndex++] = target; } System.arraycopy(arguments, 0,jpContext, argumentsOffset, arguments.length); return jpContext; } // Declare Error and Warning @DeclareError("callToUnsafeCode()") static final String unsafeCodeUsageError = "This third-party code is known to result in a crash"; @DeclareWarning("callToBlockingOperations()") static final String blockingCallFromAWTWarning = "Please ensure you are not calling this from the AWT thread"; // @AspectJ provides @ DeclareParents, but rarely uses it. Instead, it uses the following @ DeclareMixin as an alternative // @The essence of the mix in implemented by AspectJ is a factory method that returns a proxy object, which is used to return a proxy wrapped with an aspect // The following code is equivalent to: declare parents: Ajia banking. domain.* implements Serializable; // Because null is returned, it can only be used as a tag that has Serializable for all the classes being cut in @DeclareMixin("ajia.banking.domain.*") public Serializable serializableMixin() { return null; } // @DeclareMixin supports a parameter that mimics dependency injection and passes the entered object to the factory // AuditorImp is an implementation of the interface Auditor, that is, a proxy for the Object @DeclareMixin("ajia.banking.domain.*") public Auditor auditorMixin(Object mixedIn) { return new AuditorImpl(mixedIn); } // To mix in several interfaces, you need to put the interfaces to be added in order in the interfaces @DeclareMixin(value="ajia.banking.domain.*", interfaces="{Auditor.class, MonitoringAgent.class}") public AuditorMonitoringAgent mixin() { return new AuditorMonitoringAgentImpl(); }
}.
/**
*Define a pointcut to intercept only the controller
*Explain:
*~ the first * represents any modifier and any return value
*~ the second * is defined in the web package or sub package
*~ third * arbitrary method
*~... Matches any number of parameters
*/
@Pointcut("execution(* com.precinct.data.controller..*.*(..))") public void logPointcut() { } //Around (same as the method name above) @org.aspectj.lang.annotation.Around("logPointcut()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { LOG.info("=====================================Method start===================================="); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); long start = System.currentTimeMillis(); String requestMethod = request.getMethod(); try { Object result = joinPoint.proceed(); long end = System.currentTimeMillis(); LOG.info("Request address:" + request.getRequestURI()); LOG.info("user IP:" + request.getRemoteAddr()); LOG.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); if ("POST".equals(requestMethod)){ LOG.info("POST Request parameters: " + getRequest(request)); }else if ("GET".equals(requestMethod)){ LOG.info("GET Request parameters: " + URLDecoder.decode(request.getQueryString(), "UTF-8" )); } LOG.info("execution time: " + (end - start) + " ms!"); LOG.info("=====================================Method End===================================="); return result; } catch (Throwable e) { long end = System.currentTimeMillis(); LOG.info("URL:" + request.getRequestURI()); LOG.info("IP:" + request.getRemoteAddr()); LOG.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); if ("POST".equals(requestMethod)){ LOG.info("POST Request parameters: " + getRequest(request)); }else if ("GET".equals(requestMethod)){ LOG.info("GET Request parameters: " + URLDecoder.decode(request.getQueryString(), "UTF-8" )); } LOG.info("execution time: " + (end - start) + " ms!"); LOG.info("=====================================Method End===================================="); String requestParam = request.getQueryString(); System.out.println("requestParam" + requestParam); System.out.println("requestParam" + requestParam); throw e; } } public static String getRequest(HttpServletRequest request){ StringBuffer sb = new StringBuffer(); BufferedReader reader = null; String inputParam = ""; try { reader = request.getReader(); String line = ""; while((line = reader.readLine()) != null) { sb.append(line); } inputParam = URLEncoder.encode(sb.toString(), HTTP.UTF_8); inputParam = URLDecoder.decode(inputParam, HTTP.UTF_8); } catch (Exception e) { inputParam = ""; } return inputParam; }