Spring Boot 之 性能日志

学习在Spring Boot应用程序中创建基于Aspectj的拦截器,以基于aop拦截方法的方法执行所花费的时间来编写性能日志记录

1. Maven依赖

要添加AOP支持,我们必须在应用程序中包括spring-boot-starter-aop依赖项。

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.company</groupId>
	<artifactId>SpringBootEhcache</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>SpringBootEhcache</name>
	<url>http://maven.apache.org</url>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.6.RELEASE</version>
		<relativePath />
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<skipTests>true</skipTests>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

如果您没有使用Spring boot,那么请添加以下依赖项。

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aop</artifactId>
	<version>5.0.1.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.8.12</version>
</dependency>

2.性能记录方面

创建一个spring bean,并在类上使用注解@Aspect使其成为AOP方面。它将具有可以拦截方法并围绕这些方法应用建议的方法。

如果您未使用Spring Boot 自动配置,请确保同时使用@EnableAspectJAutoProxy注解以及@Configuration启用aop支持。

在给定的类中,我们对package中类中存在的所有方法使用了@Around建议com.company.service

我们使用StopWatch类来捕获方法的开始时间和方法的结束时间。通过从结束时间中减去开始时间,我们可以获得执行方法所需的总时间。

ProceedingJoinPoint类参数为我们提供的类名和方法名称,其将被执行。

最后,我们将所有内容以所需的格式记录在日志文件中。

package com.company.aop;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

@Aspect
@Component
public class LoggingAspect 
{	
	private static final Logger LOGGER = LogManager.getLogger(LoggingAspect.class);

	//AOP expression for which methods shall be intercepted
	@Around("execution(* com.company.service..*(..)))")
	public Object profileAllMethods(ProceedingJoinPoint proceedingJoinPoint) throws Throwable 
	{
		MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
		
		//Get intercepted method details
		String className = methodSignature.getDeclaringType().getSimpleName();
		String methodName = methodSignature.getName();
		
		final StopWatch stopWatch = new StopWatch();
		
		//Measure method execution time
		stopWatch.start();
		Object result = proceedingJoinPoint.proceed();
		stopWatch.stop();

		//Log method execution time
		LOGGER.info("Execution time of " + className + "." + methodName + " :: " + stopWatch.getTotalTimeMillis() + " ms");

		return result;
	}
}

3.类和拦截方法

出于演示目的,我们正在编写一个非常简单的管理器类和一个方法。AOP将截获该方法并针对该方法应用建议。建议实际上是在衡量方法的执行时间。

package com.company.service;

import java.util.HashMap;

import org.springframework.stereotype.Service;

import com.company.domain.Employee;

@Service
public class EmployeeManager 
{
	static HashMap<Long, Employee> db = new HashMap<>();
	
	static {
		db.put(1L, new Employee(1L, "Alex", "Gussin"));
		db.put(2L, new Employee(2L, "Brian", "Schultz"));
	}
	
	public Employee getEmployeeById(Long id) {
		return db.get(id);
	}
}
package com.company.domain;

import java.io.Serializable;

public class Employee implements Serializable 
{
	private static final long serialVersionUID = 5517244812959569947L;
	
	private Long id;
	private String firstName;
	private String lastName;

	public Employee() {
		super();
	}

	public Employee(Long id, String firstName, String lastName) {
		super();
		this.id = id;
		this.firstName = firstName;
		this.lastName = lastName;
	}

	//Getters and setters

	@Override
	public String toString() {
		return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + "]";
	}
}

4. Spring Boot性能日志记录示例

要检查日志记录,请启动spring boot应用程序并访问该方法。

package com.company;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;

import com.company.service.EmployeeManager;

@SpringBootApplication
public class Application {

	@Autowired
	private EmployeeManager employeeManager;

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

	@Bean
	public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
		return args -> {

			System.out.println(employeeManager.getEmployeeById(1L));

		};
	}
}

程序输出。

16:29:25.031 [main] INFO  com.company.aop.LoggingAspect - Execution time of EmployeeManager.getEmployeeById :: 9 ms

Employee [id=1, firstName=Alex, lastName=Gussin]

显然,现在我们能够根据所有拦截方法的方法执行时间来衡量和记录性能

学习愉快!

saigon has written 1440 articles

Leave a Reply