`

应用Spring AOP(六)-------Annotation注解配置方式

阅读更多

Spring AOP的注解方式在官网的doc文档里也有详细的说明:http://docs.spring.io/spring/docs/2.0.8/reference/aop.html

还是上篇日志的示例工程,现在换成Annotation注解的方式来配置AOP,工程结构一样的:

 AllLogAdvice类代码变成了如下:

package com.aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class AllLogAdvice {
	private Logger logger = Logger.getLogger(AllLogAdvice.class);

	// @Pointcut("execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")
	// @Pointcut("within(com.test.spring.aop.pointcutexp..*)")
	// @Pointcut("this(com.test.spring.aop.pointcutexp.Intf)")
	// @Pointcut("target(com.test.spring.aop.pointcutexp.Intf)")
	// @Pointcut("@within(org.springframework.transaction.annotation.Transactional)")
	// @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
	// @Pointcut("args(String)")
	@Pointcut("execution(* com.service.UserService.add*(..)) || execution(* com.service.UserService.delete*(..))")
	public void pointcut1() {
		// 定义一个pointcut,下面用Annotation标注的通知方法可以公用这个pointcut
	}

	// 前置通知
	// 拦截参数为一个String类型的方法
	@Before("pointcut1() && args(temp)")
	public void myBeforeAdvice(String temp) {// 如果需要知道拦截的方法的信息,也可以需添加JoinPoint参数
		String logInfoText = "这是前置通知" + temp;
		// 将日志信息写入配置的文件中
		logger.info(logInfoText);
	}

	// 后置通知
	// 拦截 返回类型为String 的方法
	@AfterReturning(pointcut = "pointcut1()", returning = "result")
	public void myAfterReturnAdvice(String result) {
		logger.info("这是后置通知  " + " result: " + result);
	}

	// 最终置通知
	@After("execution(* com.service.UserService.add*(..))")
	public void doAfter() {
		logger.info("这是最终通知");
	}

	// 异常通知
	@AfterThrowing(pointcut = "pointcut1()", throwing = "e")
	public void myThrowingAdvice(JoinPoint jionpoint, Exception e) {
		// 获取被调用的类名
		String targetClassName = jionpoint.getTarget().getClass().getName();
		// 获取被调用的方法名
		String targetMethodName = jionpoint.getSignature().getName();
		// 日志格式字符串
		String logInfoText = "异常通知:执行" + targetClassName + "类的"
				+ targetMethodName + "方法时发生异常";
		// 将日志信息写入配置的文件中
		logger.info(logInfoText);
	}

	// 环绕通知
	// @Around(value="pointcut1()")
	@Around("pointcut1()")
	public Object myAroundAdvice(ProceedingJoinPoint jionpoint)
			throws Throwable {
		// 获取被调用的方法名
		String targetMethodName = jionpoint.getSignature().getName();
		Object o = jionpoint.proceed();
		String logInfoText = "这是环绕通知:" + targetMethodName;
		logger.info(logInfoText);
		//Object o = jionpoint.proceed();//注意写到这儿的话,环绕通知和其它通知的顺序
		return o;
	}
}

 代码里加了很多注释说明,注意这儿多了一个最终通知。aop.xml文件的内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans
	xmlns="http://www.springframework.org/schema/beans"	
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
	
	<bean id="myUserService" class="com.service.UserService"></bean>
		
	<bean id="allLogAdvice" class="com.aop.AllLogAdvice"></bean>	
	
	<aop:aspectj-autoproxy />
	
	<!--  如果不声明AllLogAdvice的bean,可以在com.aop下的类加上@Component
	<context:component-scan base-package="com.aop"/> 
	-->
</beans>

 注意这里添加了<aop:aspectj-autoproxy />,而且声明了com.aop.AllLogAdvice的bean,如果不声明这个bean的话,在这个类的头上添加@Component,然后通过component-scan扫描也可以。

这儿我把UserService类稍微改了一下:

package com.service;

public class UserService implements IUserService {

	public int addUser(String name, int age) {
		//省略诸如操作数据库等复杂的逻辑操作
		System.out.println("add user "+ name +" successfully");
		return 1;
	}

	public void deleteUser(String name) {
		//省略诸如操作数据库等复杂的逻辑操作
		System.out.println("deleted one user named " + name);
		//throw new RuntimeException("这是特意抛出的异常信息!");
	}
}

addUser方法改成了int型的返回值,deleteUser方法依然是void。

MainTest主测试类代码没有变化:

package com.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.service.IUserService;

public class MainTest {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"aop.xml");
		IUserService userService = (IUserService) context
				.getBean("myUserService");

		userService.addUser("ton", 56);
		userService.deleteUser("ton");
	}
}

 

 好啦,看看执行结果:

add user ton successfully
[INFO ] [14:48:43] com.aop.AllLogAdvice - 这是最终通知
[INFO ] [14:48:43] com.aop.AllLogAdvice - 这是环绕通知:addUser
[INFO ] [14:48:43] com.aop.AllLogAdvice - 这是前置通知ton
deleted one user named ton
[INFO ] [14:48:43] com.aop.AllLogAdvice - 这是后置通知   result: null
[INFO ] [14:48:43] com.aop.AllLogAdvice - 这是环绕通知:deleteUser

 结果发现,后置通知本来是要拦截返回值是String的方法,addUser确实没有被拦截,但是deleteUser明明是void也被拦截了。

 

工程代码在附件中。。。

  • 大小: 13 KB
分享到:
评论
2 楼 moshenglei 2017-06-06  
   
1 楼 hong782365 2015-09-30  

相关推荐

Global site tag (gtag.js) - Google Analytics