这个例子展示了如何配置Spring Aop方法评测。我们可以利用面向切面编程使用任何服务(或其他)类中的任何方法,而不在任何服务类中编写一行分析代码。面向切面编程(AOP)允许我们从服务代码中分离(通常是重复的和样板的)分析代码。
目录
Spring AOP方法剖析
我们只在单独的类中编写一次探查器代码(SimpleProfiler.java),仅此而已,其余的只是spring.xml
that has to be done for working.
所以我们可以对下面的内容进行方法分析。
- 分析任何(服务)类,
- 不接触(服务)课程和代码,
- 通过Spring Aop方法。
Spring Aop方法剖析项目结构
Spring Aop-Maven依赖项
我们将首先调查pom.xml文件所有必需的依赖项及其版本的文件。我们在这个例子中使用的是spring4。
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>hu.daniel.hari.learn.spring</groupId>
<artifactId>Tutorial-SpringAop-Profiling</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<properties>
<!-- Generic properties -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
<!-- SPRING -->
<spring.version>4.0.0.RELEASE</spring.version>
</properties>
<dependencies>
<!-- Spring (includes spring-aop)-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- AspectJ (required spring-aop dependency) -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.5</version>
</dependency>
<!-- LOG -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- This plugin is needed to define the java version in maven project. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 我们需要Spring背景作为Spring依赖项。
- Springaop还附带了spring context作为它的依赖库,因此不需要添加它。
- aspectjweaver公司是Spring Aop的依赖项,但是我们必须添加它,因为它没有为Spring Aop明确定义。
Spring服务类(待分析)
我们首先编写服务类,它有模拟短流程和长流程的方法,还有一个方法抛出异常。
package hu.daniel.hari.learn.spring.aop.profiling.service;
import org.springframework.stereotype.Component;
/**
* Example service class that we want to profile through AOP.
* (Notice that no need to insert any line of profiling code!)
*
* @author Daniel Hari
*/
@Component
public class FooService {
public void doShortJob() {
sleep(10l);
}
public void doLongJob() {
sleep(300l);
}
public void doSomethingThatThrowsException() {
throw new RuntimeException("Simulated Exception.");
}
private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
请注意,我们没有在服务类中放入任何分析代码。
SpringAOP探查器类
我们的profiler类对方法执行的处理时间毫秒做了一个简单的度量。
package hu.daniel.hari.learn.spring.aop.profiling.core.profiler;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
import org.springframework.util.StopWatch.TaskInfo;
/**
* Our profiler that
* logs process time, and remark if process had exception.
*
* @author Daniel Hari
*/
public class SimpleProfiler {
/**
* Spring AOP "around" reference method signature is bounded like this, the
* method name "profile" should be same as defined in spring.xml aop:around
* section.
**/
public Object profile(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();
stopWatch.start(proceedingJoinPoint.toShortString());
boolean isExceptionThrown = false;
try {
// execute the profiled method
return proceedingJoinPoint.proceed();
} catch (RuntimeException e) {
isExceptionThrown = true;
throw e;
} finally {
stopWatch.stop();
TaskInfo taskInfo = stopWatch.getLastTaskInfo();
// Log the method"s profiling result
String profileMessage = taskInfo.getTaskName() + ": " + taskInfo.getTimeMillis() + " ms" +
(isExceptionThrown ? " (thrown Exception)" : "");
System.out.println(profileMessage);
}
}
}
- 如您所见,我们的profile方法使用秒表来测量方法执行情况。
- 该方法从Spring Aop接收ProceedingJoinPoint对象,该对象表示在执行方法之前的方法执行连接点。这个对象还有关于要执行的方法的信息,我们可以得到。
- 我们负责通过调用该方法&8217;s proceed()来执行该方法。
- 我们确实知道异常也在执行的方法中抛出,以便记录它,但是我们将它向前抛出是为了透明,我们不想在这个级别处理异常,只想记录它。
(“;profile”;方法签名是有界的,因为Spring AOP将调用它,但是方法名可以是任何其他将在中设置的spring.xml文件.)
Spring Aop配置XML
现在我们已经准备好了迷你应用程序中需要的每个工作类。让我们创建Spring的配置文件:
spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans" xmlns:context="https://www.springframework.org/schema/context" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:aop="https://www.springframework.org/schema/aop"
xsi:schemaLocation="
https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-4.0.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-4.0.xsd
https://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- Scans the classpath for annotated components that will be auto-registered as Spring beans -->
<context:component-scan base-package="hu.daniel.hari.learn.spring.aop.profiling" />
<!-- Activates various annotations to be detected in bean classes e.g: @Autowired -->
<context:annotation-config />
<!-- AOP Configuration for profiling -->
<!-- Our profiler class that we want to use to measure process time of service methods. -->
<bean id="profiler" />
<!-- Spring AOP -->
<aop:config>
<aop:aspect ref="profiler">
<!-- Catch all method in the service package through AOP. -->
<aop:pointcut id="serviceMethod"
expression="execution(* hu.daniel.hari.learn.spring.aop.profiling.service.*.*(..))" />
<!-- For these methods use the profile named method in the profiler class we defined below. -->
<aop:around pointcut-ref="serviceMethod" method="profile" />
</aop:aspect>
</aop:config>
</beans>
- 首先,我们告诉spring,我们希望对spring组件使用类路径扫描(而不是在这个xml中一个一个地定义它们),而且我们还启用spring注解检测。
- 我们配置Spring AOP,捕捉服务包中所有类中的所有方法:
- 我们定义了一个方面,它“;切入点”;-s每个服务方法,
- 我们为这些切入点定义了一个“;around”;方法,该方法的目标是我们的SimpleProfiler’;s“;profile”;命名方法。
Spring Aop方法剖析测试类
就这样!剩下的只是我们应用程序的一个测试类。
package hu.daniel.hari.learn.spring.aop.profiling.main;
import hu.daniel.hari.learn.spring.aop.profiling.service.FooService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Example test class for Spring AOP Profiling.
*
* (remark: Exceptional calls should be put in try catch and handle ctx.close
* properly but we missed to keep simleness of this example.)
*
* @author Daniel Hari
*/
public class Main {
public static void main(String[] args) {
// Create Spring application context that configured by xml.
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/spring.xml");
// Get our service from the spring context (that we want to be profiled).
FooService fooService = ctx.getBean(FooService.class);
// Test profiling through methods calls.
for (int i = 0; i < 10; i++) {
fooService.doShortJob();
}
fooService.doLongJob();
// Test that profiler also can handle Exceptions in profiled method.
fooService.doSomethingThatThrowsException();
// Close the spring context
ctx.close();
}
}
您可以看到,从main方法启动Spring容器并获得第一个依赖注入入口点,即服务类实例是多么简单。
如果您运行,您将得到以下日志:
execution(FooService.doShortJob()): 38 ms
execution(FooService.doShortJob()): 10 ms
execution(FooService.doShortJob()): 10 ms
execution(FooService.doShortJob()): 10 ms
execution(FooService.doShortJob()): 10 ms
execution(FooService.doShortJob()): 10 ms
execution(FooService.doShortJob()): 10 ms
execution(FooService.doShortJob()): 10 ms
execution(FooService.doShortJob()): 10 ms
execution(FooService.doShortJob()): 10 ms
execution(FooService.doLongJob()): 300 ms
execution(FooService.doSomethingThatThrowsException()): 0 ms (thrown Exception)
Exception in thread "main" java.lang.RuntimeException: Simulated Exception.
at hu.daniel.hari.learn.spring.aop.profiling.service.FooService.doSomethingThatThrowsException(FooService.java:23)
...
您可以看到为每个服务方法调用生成的分析日志。您可以在同一个包或下面创建其他服务类,这些服务类也将被分析。
如果您想了解AOP概念是如何工作的,请查看下面的参考链接。如果你使用log4j.properties
file from attached source, and uncomment first line(s) you can see what’s going on under the hood.
参考文献: