一、切入点表达式
1、execution:匹配方法的执行
格式:execution(修饰符 返回值类型 包.类.方法(参数) throw 异常)
1.1修饰符,表示方法的修饰符,一般省略。
1.2返回类型 String表示返回String;void表示没有返回值;*表示返回任意类型,包括无返回值。
1.3包
hjp.spring.service 表示指定的包
hjp.spring.*.service 表示spring下子模块包含service的包
hjp.spring.service.. 表示service目录及其子目录
综合:hjp.spring.*.service..
1.4类 UserService表示指定的类;*Service表示以Service结尾;Test*表示以Test开头;*表示任意类名。
1.5方法(与类相似)
addUser表示指定方法;add*表示以add开头;*Do表示以Do结尾;*表示任意。
1.6参数 ()表示没有参数;(int)表示一个int类型参数;(int,int)表示两个int类型参数(如果是java.lang包下的可以省略,其他类型必须写完全限定类名);(..)表示
任意,包括无参。
1.7throws 异常,一般省略。
综合:execution(* hjp.spring.*.service..*.*(..))
2、within:匹配包或子包中的方法,如:within(hjp.spring.service..*)
3、this:匹配实现接口的代理对象中的方法,如:this(hjp.spring.dao.UserDao)
4、target:匹配实现接口的目标对象中的方法,如:target(hjp.spring.daoImpl.UserDao)
5、args:匹配参数格式符合标准的方法,如args(int,int)
6、bean:匹配指定的bean,如:bean("userServiceId")
二、AspectJ规定的通知类型
1、before:前置通知(应用:各种校验),在方法执行前执行,如果通知抛出异常,阻止方法运行。
2、afterReturning:后置通知(应用:常规数据处理),方法正常返回后执行,如果方法中抛出异常,通知无法执行;在方法执行后执行,所以才可以获得方法的返回值。
3、around:环绕通知(应用:可以做任何事),方法执行前后分别执行,可以阻止方法的执行。
4、afterThrowing:抛出异常通知(应用:包装异常信息),方法抛出异常后执行,如果方法没有抛出异常,无法执行。
5、after:最终通知(应用:清理现场),方法执行完毕后执行,无论方法是否有异常出现。
环绕通知类似代码块:

1try{ 2//前置通知(before) 3//手动执行目标方法 4//后置通知(after),可获得返回值 5}catch{ 6//抛出异常通知(afterThrowing),可获得具体异常信息 7}finally{ 8//最终(finally) 9}
环绕通知类似代码块
三、基于XML配置的代码示例
1、代码结构:

2、aspectj aop不是针对接口的,所有有没有接口不影响AOP实现,下面是UserService接口和UserServiceImpl实现类(目标类)代码

1package hjp.springAOP.springAspectJXml; 2 3public interface UserService { 4 void addUser(); 5 6 void updateUser(); 7}
UserService

1package hjp.springAOP.springAspectJXml; 2 3public class UserServiceImpl implements UserService { 4 5 @Override 6 public void addUser() { 7 // TODO Auto-generated method stub 8 System.out.println("aspectj xml add user"); 9 } 10 11 @Override 12 public void updateUser() { 13 // TODO Auto-generated method stub 14 //int i=9/0; 15 System.out.println("aspectj xml update user"); 16 } 17 18}
UserServiceImpl
3、切面类MyAspect代码

1package hjp.springAOP.springAspectJXml; 2 3import org.aspectj.lang.JoinPoint; 4import org.aspectj.lang.ProceedingJoinPoint; 5 6public class MyAspect { 7 public void myBefore(JoinPoint joinPoint) { 8 System.out.println("前置通知:" + joinPoint.getSignature().getName()); 9 } 10 11 public void myAfterReturning(JoinPoint joinPoint, Object ret) { 12 System.out.println("后置通知:方法名," + joinPoint.getSignature().getName() + ";返回值," + ret); 13 } 14 15 public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { 16 System.out.println("环绕通知前"); 17 // 手动执行目标方法 18 Object object = proceedingJoinPoint.proceed(); 19 System.out.println("环绕通知后"); 20 return object; 21 } 22 23 public void myAfterThrowing(JoinPoint joinPoint, Throwable e) { 24 System.out.println("目标类方法" + joinPoint.getSignature().getName() + "抛出异常:" + e.getMessage()); 25 } 26 27 public void myAfter(JoinPoint joinPoint) { 28 System.out.println("最终执行通知:方法:" + joinPoint.getSignature().getName()); 29 } 30}
MyAspect
4、beans.xml配置文件,记得添加aop命名空间和引用地址

1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd 6 http://www.springframework.org/schema/aop 7 http://www.springframework.org/schema/aop/spring-aop.xsd"> 8 <!-- 1、创建目标类 --> 9 <bean id="userServiceId" class="hjp.springAOP.springAspectJXml.UserServiceImpl"></bean> 10 <!-- 2、创建切面类 (通知) --> 11 <bean id="myAspectId" class="hjp.springAOP.springAspectJXml.MyAspect"></bean> 12 <!-- aop编程 13 如果强制使用CGLIB,则设置aop:config 属性proxy-target-class="true" 14 --> 15 <aop:config> 16 <!-- aspectj 编程 17 ref指向切面类 --> 18 <aop:aspect ref="myAspectId"> 19 <!-- 声明切入点,确定目标类上哪些方法需被增强 --> 20 <aop:pointcut expression="execution(* hjp.springAOP.springAspectJXml.*.*(..))" id="myPointCut" /> 21 <!-- 声明通知方式 --> 22 <!-- 1、前置通知 23 method切面类中具体方法名 24 pointcut-ref指向切入点(使用pointcut,也可以在通知里配置自己的切入点表达式) 25 <aop:before method="myBefore" pointcut-ref="myPointCut"/> 26 --> 27 <!-- 2、后置通知,可获取到返回值 28 returning用于设置通知的第二个参数名称,类型为Object(注意:此处参数名称要与切面类后置通知方法第二个参数名称一致) 29 <aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret"/> 30 --> 31 <!-- 3、环绕通知 32 <aop:around method="myAround" pointcut-ref="myPointCut"/> 33 --> 34 <!-- 4、抛出异常通知(测试此通知时,将目标类中updateUser方法中int i=9/0;代码注释去掉) 35 目标方法在抛出异常时执行,如果没有则不执行 36 throwing设置抛出异常通知的第二个参数,参数名称和此处设置的e一致,类型Throwable 37 <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/> 38 --> 39 <!-- 5、最终通知,即任何情况下都会执行 --> 40 <aop:after method="myAfter" pointcut-ref="myPointCut"/> 41 </aop:aspect> 42 </aop:config> 43</beans>
beans.xml
5、测试类

1package hjp.springAOP.springAspectJXml; 2 3import org.junit.Test; 4import org.springframework.context.ApplicationContext; 5import org.springframework.context.support.ClassPathXmlApplicationContext; 6 7public class TestApp { 8 @Test 9 public void demo1() { 10 String xmlPath="hjp/springAOP/springAspectJXml/beans.xml"; 11 ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath); 12 UserService userService = (UserService)applicationContext.getBean("userServiceId"); 13 userService.addUser(); 14 userService.updateUser(); 15 } 16}
测试类
四、基于注解的代码示例
1、代码结构和上面差不多

2、目标类的接口代码不变,目标类加注解后代码:

1package hjp.springAOP.springAspectJAnnotation; 2 3import org.springframework.stereotype.Service; 4 5@Service("userServiceId")//<bean id="userServiceId" class="hjp.springAOP.springAspectJAnnotation.UserServiceImpl"></bean> 6public class UserServiceImpl implements UserService { 7 8 @Override 9 public void addUser() { 10 // TODO Auto-generated method stub 11 System.out.println("aspectj xml add user"); 12 } 13 14 @Override 15 public void updateUser() { 16 // TODO Auto-generated method stub 17 //int i=9/0; 18 System.out.println("aspectj xml update user"); 19 } 20 21}
目标类
3、切面类加注解后代码(注意:代码里面使用了引用公共切入点表达式的方法):

1package hjp.springAOP.springAspectJAnnotation; 2 3import org.aspectj.lang.JoinPoint; 4import org.aspectj.lang.ProceedingJoinPoint; 5import org.aspectj.lang.annotation.After; 6import org.aspectj.lang.annotation.AfterReturning; 7import org.aspectj.lang.annotation.AfterThrowing; 8import org.aspectj.lang.annotation.Around; 9import org.aspectj.lang.annotation.Aspect; 10import org.aspectj.lang.annotation.Before; 11import org.aspectj.lang.annotation.Pointcut; 12import org.springframework.stereotype.Component; 13 14@Component//<bean id="myAspectId" class="hjp.springAOP.springAspectJAnnotation.MyAspect"></bean> 15@Aspect//<aop:aspect ref="myAspectId"> 16public class MyAspect { 17 //@Before("execution(* hjp.springAOP.springAspectJAnnotation.*.*(..))")//<aop:before method="myBefore" pointcut="myPointCut"/> 18 public void myBefore(JoinPoint joinPoint) { 19 System.out.println("前置通知:" + joinPoint.getSignature().getName()); 20 } 21 //@AfterReturning(value="execution(* hjp.springAOP.springAspectJAnnotation.*.*(..))",returning="ret") 22 public void myAfterReturning(JoinPoint joinPoint, Object ret) { 23 System.out.println("后置通知:方法名," + joinPoint.getSignature().getName() + ";返回值," + ret); 24 } 25 //编写共有的切入点表达式 26 @Pointcut("execution(* hjp.springAOP.springAspectJAnnotation.*.*(..))") 27 private void myPointCut(){} 28 //@Around("myPointCut()")//注意加括号 29 public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { 30 System.out.println("环绕通知前"); 31 // 手动执行目标方法 32 Object object = proceedingJoinPoint.proceed(); 33 System.out.println("环绕通知后"); 34 return object; 35 } 36 //@AfterThrowing(value="myPointCut()",throwing="e") 37 public void myAfterThrowing(JoinPoint joinPoint, Throwable e) { 38 System.out.println("目标类方法" + joinPoint.getSignature().getName() + "抛出异常:" + e.getMessage()); 39 } 40 @After("myPointCut()") 41 public void myAfter(JoinPoint joinPoint) { 42 System.out.println("最终执行通知:方法:" + joinPoint.getSignature().getName()); 43 } 44}
切面类
4、beans.xml配置文件,注意新加context和AOP命名空间及引用地址
1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/aop 8 http://www.springframework.org/schema/aop/spring-aop.xsd 9 http://www.springframework.org/schema/context 10 http://www.springframework.org/schema/context/spring-context.xsd"> 11 <!-- spring注解扫描 --> 12 <context:component-scan base-package="hjp.springAOP.springAspectJAnnotation"></context:component-scan> 13 <!-- 使AOP注解生效 --> 14 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 15</beans>
5、测试类

1package hjp.springAOP.springAspectJAnnotation; 2 3import org.junit.Test; 4import org.springframework.context.ApplicationContext; 5import org.springframework.context.support.ClassPathXmlApplicationContext; 6 7public class TestApp { 8 @Test 9 public void demo1() { 10 String xmlPath="hjp/springAOP/springAspectJAnnotation/beans.xml"; 11 ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath); 12 UserService userService = (UserService)applicationContext.getBean("userServiceId"); 13 userService.addUser(); 14 userService.updateUser(); 15 } 16}
测试类
3、