AOP Brief introduction
name : Section oriented programming
effect : Reduce the coupling of code in the system , And in the condition of not changing the original code, the function of the original method is extended .
The formula : AOP = Pointcut expression + Notification method
Notification type
1. Pre notice Before the target method is executed
2. The rear notice The target method is executed after execution
3. Abnormal notice When an exception is thrown during the execution of the target method
4. Final notice A notice to be executed at any time
characteristic : The four types of notification mentioned above Cannot interfere with the execution of the target method . It is generally used to record the running state of a program .【 monitor 】
5. Surrounding the notification A notification method that is executed before and after the target method is executed This method can control whether the target method runs or not .joinPoint.proceed(); Function as powerful .
Pointcut expression
Pointcut expression is a judgment of whether a program enters the notification (IF).
effect : When the program is running , Only when the pointcut expression is satisfied can the notification method be executed , Realize business expansion .
species ( How to write it ):
1.bean(bean The name of bean Of ID) Can only intercept a specific bean object , Only one object can be matched .
for example :bean("itemServiceImpl")
2.within( Package name . Class name ) within("com.jt.service.*") Indicates that multiple objects can be matched .
3.execution( return type Package name . Class name . Method name ( parameter list )) The most powerful use
for example : execution( com.jt.service...*(..)) The return value type is arbitrary com.jt.service All methods of all classes under the package will be intercepted .
[email protected]( Package name . Annotated name ) Match according to the annotation .
AOP Introductory cases
package com.jt.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect // I am a AOP Section class
@Component // Give the class to spring Container management
public class CacheAOP {
// The formula : Pointcut expression + Notification method
/**
* About the use of pointcut expressions
* coarse-grained
* 1.bean(bean Of id) One class
* 2.within( Package name . Class name ) Multiple classes
* fine-grained
* 1.
*/
//@Pointcut("bean(itemCatSercviceImpl)")
// .* Represents the first level directory under the current package .
// ..* Represents the multi-level directory under the current package
/*@Pointcut("within(com.jt.service..*)")
public void pointCut(){
// Define pointcut expression , In order to occupy the space
}*/
// Define pre notice , Binding to pointcuts @Before("pointCut()")
// Or in a simpler way : There's no need to define pointcut methods pointCut(),
// Direct binding bean:@before(“bean(itemCatSercviceImpl)”)
/* The difference between the two :
* [email protected]("pointCut()") Represents a reference to a pointcut expression , For multiple notifications with pointcuts
* [email protected](“bean(itemCatSercviceImpl)”) For a single notification , No need to reuse
* */
/**@Before("pointCut()")
public void before(){
System.out.println(" I'm advance notice ");
}
@AfterReturning("pointCut()")
public void afterreturn(){
System.out.println(" I'm a post notification ");
}*/
@Before("pointCut()")
public void before(JoinPoint joinPoint){
//JoinPoint: Connection point method
//getStaticPart() Method signature representing the join point
//getName() Method name
String methodName = joinPoint.getSignature().getName();
//getDeclaringTypeName() Get the full path name of the class com.jt.service.ItemCatSercviceImpl
String className = joinPoint.getSignature().getDeclaringTypeName();
System.out.println(className+"."+methodName);
//getTarget() Represents the target object
//getTarget().getClass() Get the type of the target object
Class<?> targetClass = joinPoint.getTarget().getClass();
// Get the object's parameters
Object[] args = joinPoint.getArgs();
// Get execution time
Long startTime= System.currentTimeMillis();
System.out.println(" Target method type "+targetClass);
System.out.println(" execution time :"+startTime+" millisecond ");
}
/**
* The circular notification States
* matters needing attention :
* ProceedingJoinPoint It can only be used in surround notification
* 1. Surround notification must add parameters ProceedingJoinPoint
* 2.ProceedingJoinPoint Can only be used around notification
* 3.ProceedingJoinPoint If it is a parameter, it must be in the first place of the parameter
*/
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint){
System.out.println(" Surround notification begins !!!");
Object result=null;
try {
result=joinPoint.proceed();// Execute the next notification or target method
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println(" End of surround notification !!!");
return result;
}
}
About AOP Realization Redis
Custom cache annotations
problem : How to control , Which methods need caching ?【cacheFind() Query methods 】
Solution : Define in the form of a custom annotation , If method execution requires caching , Then mark the annotation .
Notes on notes :
1. Annotated name :cacheFind
2. Property parameters :
1.key: It should be added manually by the user himself , Generally, after adding the business name, the dynamic splicing forms the unique key.
2.seconds: The user can specify the timeout for the data .
// Customize an annotation
@Target(ElementType.METHOD)// This annotation is only valid for methods
@Retention(RetentionPolicy.RUNTIME)// The operation period is valid
public @interface CacheFind {
String preKey();// User ID key The prefix of .
int seconds() default 0;// If the user does not write, it means that there is no need to time out , If it is written, the user shall prevail .
}
edit CacheAOP
package com.jt.aop;
import com.jt.anno.CacheFind;
import com.jt.util.ObjectMapperUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import java.util.Arrays;
@Aspect // I am a AOP Section class
@Component // Give the class to spring Container management
public class CacheAOP {
@Autowired
private Jedis jedis;
/** AOP Realization Redis cache
* section = The breakthrough point + Notification method
* Annotations associated + Surrounding the notification Control whether the target method is implemented
*
* difficulty :
* 1. Get the annotation object , Pass the annotation as an argument
* 2. Dynamic generation key prekey+ User parameter array
* 3. How to get the return value type of a method
*/
@Around("@annotation(cacheFind)")
public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind){
System.out.println(" Annotation blocking takes effect ");
Object result=null;
try {
// Splicing redis Storing data key
Object[] args=joinPoint.getArgs();
String key=cacheFind.preKey()+"::"+ Arrays.toString(args);
// Inquire about redis Then judge whether there is data
if(jedis.exists(key)){
// Express redis There's data in , There is no need to execute the target method
String json = jedis.get(key);
// Get the return value type of the method dynamically Upward transformation Move down
MethodSignature methodSignature=(MethodSignature)joinPoint
.getSignature();
// It means that the client will return whatever type it comes from
Class returnType = methodSignature.getReturnType();
// Need to put json String is converted to an object
result=ObjectMapperUtil.toObj(json, returnType);
System.out.println("redis Data in cache ");
}else{
// Indicates that the data does not exist , You need to query in the database
result=joinPoint.proceed();// Implementation target method and notification
// Store the query data in redis In cache
String json = ObjectMapperUtil.toJson(result);
// Determine if a timeout is required
if(cacheFind.seconds()>0){
jedis.setex(key, cacheFind.seconds(), json);
}else{
jedis.set(key, json);
}
System.out.println("aop Execute target method query database ");
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return result;
}
}