This is the sixth day of my participation in the August More text Challenge. For details, see: August More Text Challenge

preface

In the work often encountered the need for persistent log situation, especially the kind of platform, other people’s data sent in, you give others, a problem can not find the log, it is not shit is shit

Of course, the specific log persistence solution depends on the architecture, design, and business, and in any case, the time it takes to execute this part of the code can’t be ignored


Emergence of problems

Suppose the requirement is that a user logs in to the backend system, and the way to persist the log is to store it in a table in the database. A very simple requirement, according to the normal synchronization code logic might be written like this

LoginServiceImpl

@override public String login(String username, String password) { Cache token and other logical String token = "generate new token and refresh token "; // Perpetuate logs to the database LoginLogEntity loginLog = getLoginLog(username, password); loginLogDao.save(loginLog); return token; }Copy the code

This has two disadvantages:

  • Since the log persistence logic is synchronous, if the log persistence logic fails, an exception will be reported when the user logs in
  • If the log-saving logic were more complex, the user would have to wait for the execution time of this piece of code every time he logged in


Implement asynchronous logging using AOP

Use AOP to make an otherwise synchronous operation asynchronous

For ease of maintenance, we need to create a custom annotation. If you do not use annotations, maintenance colleagues may not know that you are weaving AOP into the method, which may cause code logic to be ignored and increase maintenance costs. Another reason is that the form of annotations increases reusability. With custom annotations we can achieve automatic logging (in, out, response time, etc.), separation of non-business core code, etc

Aspectj dependencies need to be introduced:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>
Copy the code

Create a custom annotation:

@Retention(RetentionPolicy.RUNTIME)
public @interface LoginLog {
    // Define an annotation parameter that identifies the different systems logged in to
    String system(a);
}
Copy the code

Create an implementation of this annotation:

@Aspect
@Component
@Slf4j
public class LoginLogAspect {
    @Pointcut("@annotation(com.suckmydisk.mapstructdemo.annotation.LoginLog)")
    public void pointCut(a) {
        // Set the weaving point to a custom annotation
    }

    /** The following code is called after the annotated method is run
    @AfterReturning(value = "pointCut() && @annotation(loginLog)", returning = "token")
    public void loginLog(JoinPoint joinPoint, String token, LoginLog loginLog) {
        Object[] args = joinPoint.getArgs();
        String username = args[0].toString();
        String password = args[1].toString();
        String loginSystem = loginLog.system();

        log.info(Username :{}, password :{}, token:{}, login system :{}", username, password, token, loginSystem); }}Copy the code

Actual use:

Add a logging annotation to the login method of the UserServiceImpl class:

@Service
public class UserServiceImpl implements UserService {
    @Override
    @loginlog (system = "background management system ")
    public String login(String username, String password) {
        return "Generated new Token"; }}Copy the code

Called in LoginController

@PostMapping("/login")
public void login(@RequestParam String username,
                  @RequestParam String password) {
    userService.login(username, password);
}
Copy the code

After calling the login interface, the console outputs:


conclusion

  1. inLoginLogAspect.javaloginLog()So in the method we’re configuring@AfterReturningThis is after the annotated method returns a valueloginLog()To be triggered
  2. The same isloginLog()Method, as used by&& @annotation(loginLog)To get the value of an attribute in an annotation, so add parameters to the methodLoginLog loginLog, and the custom annotation should be added@Retention(RetentionPolicy.RUNTIME)Otherwise, an error will be reported
  3. Since the principles of AOP are based on dynamic proxies, calls between real objects can invalidate AOP, so be careful when programming
  4. Write more notes, leave less pit, to the new partner left the last gentle