Spring AOP方法分析

 

Spring AOP方法分析

 

此示例显示如何配置Spring AOP方法概要分析。我们可以在任何服务(或其他)类中使用Spring AOP和任何方法,而无需在任何服务类中编写任何一行分析代码。面向方面编程(AOP)允许我们将(通常是重复的和样板)分析代码与服务代码分开。

目录[ 隐藏 ]

Spring AOP方法分析

我们只在一个单独的类(SimpleProfiler.java)中编写我们的探查器代码一次,这就是全部,其余的只有AOP配置spring.xml才能完成工作。

因此,我们可以对以下方法进行方法分析。

  1. 分析任何(服务)类,
  2. 没有触及(服务)类的代码,
  3. 通过Spring-AOP方法。

Spring AOP方法分析项目结构

Spring AOP方法分析示例

Spring AOP Maven依赖项

我们将首先查看我们的pom.xml文件,了解所有必需的依赖项及其版本。我们在这个例子中使用Spring 4。


<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>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-context作为Spring依赖。
  • spring-aop还带有spring-context作为它的依赖库,所以不需要添加它。
  • aspectjweaver是spring-aop的依赖项,但我们必须添加它,因为它没有为spring-aop明确定义。

Spring Service类(待分析)

我们首先编写我们的服务类,它有模拟短进程和长进程的方法,还有一个抛出异常的方法。

 


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();
		}
	}
}

请注意,我们没有在服务类中放置任何分析代码。

Spring AOP 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);
		}
	}
	
}
  1. 如您所见,我们的配置文件方法使用秒表来测量方法执行。
  2. 该方法从Spring-AOP接收ProceedingJoinPoint对象,该对象在执行该方法之前表示此情况下的方法执行关节点。该对象还有关于我们可以获得的要执行的方法的信息。
  3. 我们负责通过调用它的proceed()来执行该方法。
  4. 我们也知道在执行的日志记录方法中抛出的异常,但是我们将其推向透明,我们不希望在此级别处理异常,只记录它。

(“profile”方法签名受限于Spring AOP将调用它,但方法名称可以是将在spring.xml中设置的任何其他内容。)

 

Spring AOP配置XML

现在我们准备好了迷你应用程序中所需的每个工作类。让我们创建Spring的配置文件:

spring.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context-4.0.xsd
		http://www.springframework.org/schema/aop
        http://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" class="hu.daniel.hari.learn.spring.aop.profiling.core.profiler.SimpleProfiler" />

	<!-- 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>
  1. 首先我们告诉spring我们要对Spring组件使用类路径扫描(而不是在这个xml中逐个不方便地定义它们),并且我们还启用了Spring注释检测。
  2. 我们配置Spring-AOP,以捕获服务包中所有类的所有方法:
    1. 我们定义了一个“切入点”的方面 - 每个服务方法,
    2. 我们为这些切入点定义了一个“around”方法,该方法以SimpleProfiler的“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来自附加源的文件,并取消注释第一行,您可以看到幕后发生了什么。

参考文献:
使用Spring进行面向方面编程

您可以从下面的链接下载完整的maven项目源。

下载Spring AOP示例项目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值