`

05-Spring3 AOP C_基于@AspectJ的AOP

阅读更多

 

         Spring除了支持Schema方式配置AOP,还支持注解方式:使用@AspectJ风格的切面声明。

 

一、启用对@AspectJ的支持

 

Spring默认不支持@AspectJ风格的切面声明,为了支持需要使用如下配置:

<aop:aspectj-autoproxy/>

这样Spring就能发现@AspectJ风格的切面并且将切面应用到目标对象。

 

二、声明切面

 

@AspectJ风格的声明切面非常简单,使用@Aspect注解进行声明:

	@Aspect()
	Public class Aspect{
	……
	}

 

然后将该切面在配置文件中声明为Bean后,Spring就能自动识别并进行AOP方面的配置:

<bean id="aspect" class="……Aspect"/>

该切面就是一个POJO,可以在该切面中进行切入点及通知定义,接着往下看吧。

 

三、声明切入点

	@Pointcut(value="切入点表达式", argNames = "参数名列表")
	public void pointcutName(……) {}

          value指定切入点表达式;

         argNames指定命名切入点方法参数列表参数名字,可以有多个用分隔,这些参数将传递给通知方法同名的参数,同时比如切入点表达式“args(param)”将匹配参数类型为命名切入点方法同名参数指定的参数类型。

         pointcutName切入点名字,可以使用该名字进行引用该切入点表达式。

	@Pointcut(value="execution(* com.iflytek..*.sayAdvisorBefore(..)) && args(param)", argNames = "param")
	public void beforePointcut(String param) {}

定义了一个切入点,名字为“beforePointcut”,该切入点将匹配目标方法的第一个参数类型为通知方法实现中参数名为“param”的参数类型。

  

四、声明通知

 

@AspectJ风格的声明通知也支持5种通知类型:

 

1、前置通知

 

使用org.aspectj.lang.annotation 包下的@Before注解声明;

@Before(value = "切入点表达式或命名切入点", argNames = "参数列表参数名")  

           value指定切入点表达式或命名切入点;

           argNamesSchema方式配置中的同义。

  

2、后置返回通知

 

         使用org.aspectj.lang.annotation 包下的@AfterReturning注解声明;

	@AfterReturning(
			value="切入点表达式或命名切入点",
			pointcut="切入点表达式或命名切入点",
			argNames="参数列表参数名",
			returning="返回值对应参数名")

         value指定切入点表达式或命名切入点;

         pointcut同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;

         argNamesreturningSchema方式配置中的同义。

  

3、后置异常通知

 

使用org.aspectj.lang.annotation 包下的@AfterThrowing注解声明;

	@AfterThrowing (
			value="切入点表达式或命名切入点",
			pointcut="切入点表达式或命名切入点",
			argNames="参数列表参数名",
			throwing="异常对应参数名")

           value指定切入点表达式或命名切入点;

           pointcut同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;

           argNamesthrowingSchema方式配置中的同义。

  

4、后置最终通知

 

         使用org.aspectj.lang.annotation 包下的@After注解声明;

	@After (
			value="切入点表达式或命名切入点",
			argNames="参数列表参数名")

          value指定切入点表达式或命名切入点;

          argNamesSchema方式配置中的同义;

  

5、环绕通知

 

使用org.aspectj.lang.annotation 包下的@Around注解声明;

	@Around (
			value="切入点表达式或命名切入点",
			argNames="参数列表参数名")

          value指定切入点表达式或命名切入点;

          argNamesSchema方式配置中的同义;

  

Demo

 1、定义接口和实现,在此我们就使用Schema风格时的定义;

 2、切面HelloWorldAnnotationAspect.java

package com.iflytek.aop;

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.DeclareParents;
import org.aspectj.lang.annotation.Pointcut;

import com.iflytek.service.IIntroductionService;

/**
 * @author xdwang
 * 
 * @create 2013-8-10 下午7:05:50
 * 
 * @email:xdwangiflytek@gmail.com
 * 
 * @description 切面
 * 
 */
@Aspect//定义切面
public class HelloWorldAnnotationAspect {

	/**
	 * @descrption 定义切入点
	 * @author xdwang
	 * @create 2013-8-9下午7:08:40
	 * @param param
	 */
	@Pointcut(value = "execution(* com.iflytek..*.sayBefore(java.lang.String)) && args(param)", argNames = "param")
	public void beforePointcut(String param) {
	}

	/**
	 * @descrption 前置通知
	 * @author xdwang
	 * @create 2013-8-9下午7:08:18
	 * @param param
	 */
	@Before(value = "beforePointcut(param)", argNames = "param")
	public void beforeAdvice(String param) {
		System.out.println("===========before advice param:" + param);
	}

	/**
	 * @descrption 后置返回通知
	 * @author xdwang
	 * @create 2013-8-9下午7:09:04
	 * @param retVal
	 */
	@AfterReturning(value = "execution(* com.iflytek..*.sayBefore(..))", pointcut = "execution(* com.iflytek..*.sayAfterReturning(..))", argNames = "retVal", returning = "retVal")
	public void afterReturningAdvice(Object retVal) {
		System.out.println("===========after returning advice retVal:" + retVal);
	}

	/**
	 * @descrption 后置异常通知
	 * @author xdwang
	 * @create 2013-8-9下午7:09:45
	 * @param exception
	 */
	@AfterThrowing(value = "execution(* com.iflytek..*.sayAfterThrowing(..))", argNames = "exception", throwing = "exception")
	public void afterThrowingAdvice(Exception exception) {
		System.out.println("===========after throwing advice exception:" + exception);
	}

	/**
	 * @descrption 后置最终通知
	 * @author xdwang
	 * @create 2013-8-9下午7:09:55
	 */
	@After(value = "execution(* com.iflytek..*.sayAfterFinally(..))")
	public void afterFinallyAdvice() {
		System.out.println("===========after finally advice");
	}
	
	/**
	 * @descrption 环绕通知
	 * @author xdwang
	 * @create 2013-8-9下午7:10:41
	 * @param pjp
	 * @return
	 * @throws Throwable
	 */
	@Around(value = "execution(* com.iflytek..*.sayAround(..))")
	public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("===========around before advice");
		Object retVal = pjp.proceed(new Object[] { "replace" });
		System.out.println("===========around after advice");
		return retVal;
	}

	@Around(value = "this(com.iflytek.service.IIntroductionService+)")
	public Object thisPointcut(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("===========around sssss advice");
		Object retVal = pjp.proceed();
		System.out.println("===========around ssss advice");
		return retVal;
	}

}

 

Resources/adviceAnnotation.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	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-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

	<aop:aspectj-autoproxy />

	<bean id="helloWorldService" class="com.iflytek.service.impl.HelloWorldService" />

	<bean id="aspect" class="com.iflytek.aop.HelloWorldAnnotationAspect" />

</beans>

 Test

package com.iflytek.test;

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

import com.iflytek.service.IHelloWorldService;
import com.iflytek.service.IIntroductionService;

/**
 * @author xdwang
 * 
 * @create 2013-8-9 下午7:58:22
 * 
 * @email:xdwangiflytek@gmail.com
 * 
 * @description 测试
 * 
 */
public class AopTest {
	
	/**
	 * @descrption 前置通知  
	 * @author xdwang
	 * @create 2013-8-9下午7:08:55
	 */
	@Test
	public void testAnnotationBeforeAdvice() {
		System.out.println("======================================");
		ApplicationContext ctx = new ClassPathXmlApplicationContext("adviceAnnotation.xml");
		IHelloWorldService helloworldService = ctx.getBean("helloWorldService", IHelloWorldService.class);
		helloworldService.sayBefore("before");
		System.out.println("======================================");
	}

	/**
	 * @descrption 后置返回通知 
	 * @author xdwang
	 * @create 2013-8-9下午7:09:28
	 */
	@Test
	public void testAnnotationAfterReturningAdvice() {
		System.out.println("======================================");
		ApplicationContext ctx = new ClassPathXmlApplicationContext("adviceAnnotation.xml");
		IHelloWorldService helloworldService = ctx.getBean("helloWorldService", IHelloWorldService.class);
		helloworldService.sayAfterReturning();
		System.out.println("======================================");
	}

	/**
	 * @descrption 后置异常通知 
	 * @author xdwang
	 * @create 2013-8-9下午7:09:39
	 */
	@Test(expected = RuntimeException.class)
	public void testAnnotationAfterThrowingAdvice() {
		System.out.println("======================================");
		ApplicationContext ctx = new ClassPathXmlApplicationContext("adviceAnnotation.xml");
		IHelloWorldService helloworldService = ctx.getBean("helloWorldService", IHelloWorldService.class);
		helloworldService.sayAfterThrowing();
		System.out.println("======================================");
	}

	/**
	 * @descrption 后置最终通知 
	 * @author xdwang
	 * @create 2013-8-9下午7:10:03
	 */
	@Test(expected = RuntimeException.class)
	public void testAnnotationAfterFinallyAdvice() {
		System.out.println("======================================");
		ApplicationContext ctx = new ClassPathXmlApplicationContext("adviceAnnotation.xml");
		IHelloWorldService helloworldService = ctx.getBean("helloWorldService", IHelloWorldService.class);
		helloworldService.sayAfterFinally();
		System.out.println("======================================");
	}

	/**
	 * @descrption 环绕通知 
	 * @author xdwang
	 * @create 2013-8-9下午7:10:15
	 */
	@Test
	public void testAnnotationAroundAdvice() {
		System.out.println("======================================");
		ApplicationContext ctx = new ClassPathXmlApplicationContext("adviceAnnotation.xml");
		IHelloWorldService helloworldService = ctx.getBean("helloWorldService", IHelloWorldService.class);
		helloworldService.sayAround("haha");
		System.out.println("======================================");
	}

}

 

切面、切入点、通知全部使用注解完成:

        1)使用@AspectPOJO声明为切面;

        2)使用@Pointcut进行命名切入点声明,同时指定目标方法第一个参数类型必须是java.lang.String,对于其他匹配的方法但参数类型不一致的将也是不匹配的,通过argNames = "param"指定了将把该匹配的目标方法参数传递给通知同名的参数上;

        3)使用@Before进行前置通知声明,其中value用于定义切入点表达式或引用命名切入点;

        4)配置文件需要使用<aop:aspectj-autoproxy/>来开启注解风格的@AspectJ支持;

        5)需要将切面注册为Bean,如“aspect”Bean

        6)测试代码完全一样。

  

结果:

 

1、	前置通知
==========================================
===========before advice param:before
============say before
==========================================
2、后置返回通知
======================================
============after returning
===========after returning advice retVal:true
3、后置异常通知
======================================
============before throwing
===========after throwing advice exception:java.lang.RuntimeException
4、后置最终通知
======================================
============before finally
===========after finally advice
5、环绕通知
======================================
===========around before advice
===========around sssss advice
============around param:replace
===========around ssss advice
===========around after advice
======================================

 

五、引入

 

@AspectJ风格的引入声明在切面中使用org.aspectj.lang.annotation包下的@DeclareParents声明:

 

@DeclareParents(
			value=" AspectJ语法类型表达式",
			defaultImpl=引入接口的默认实现类)
			private Interface interface;

         value匹配需要引入接口的目标对象的AspectJ语法类型表达式;与Schema方式中的types-matching属性同义;

          private Interface interface指定需要引入的接口;

          defaultImpl指定引入接口的默认实现类,没有与Schema方式中的delegate-ref属性同义的定义方式;

 

	@DeclareParents(value = "com.iflytek..*.IHelloWorldService+", defaultImpl = com.iflytek.service.impl.IntroductionService.class)
	private IIntroductionService introductionService;

 

	/**
	 * @descrption 引入 
	 * @author xdwang
	 * @create 2013-8-9下午7:10:30
	 */
	@Test
	public void testAnnotationIntroduction() {
		System.out.println("======================================");
		ApplicationContext ctx = new ClassPathXmlApplicationContext("adviceAnnotation.xml");
		IIntroductionService introductionService = ctx.getBean("helloWorldService", IIntroductionService.class);
		introductionService.induct();
		System.out.println("======================================");
	}

 

======================================
=========introduction
======================================

 

转自http://jinnianshilongnian.iteye.com/

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics