Spring基础学习(九)——基于AspectJ的两种AOP实现方式
2018-02-04 23:57
1076 查看
AspectJ实现AOP的区别:aop联盟定义通知类型具有特性接口,必须实现相应的接口,从而确定方法名称。 Aspectj 通知类型只定义类型名称以及方法格式,不用实现接口。
AspectJ的通知类型:
before:前置通知(应用:各种校验) 在方法执行前执行,如果通知抛出异常,阻止方法运行
afterReturning:后置通知(应用:常规数据处理) 方法正常返回后执行,如果方法中抛出异常,通知无法执行。因为必须在方法执行后才执行,所以可以获得方法的返回值。
around:环绕通知(应用:十分强大,可以做任何事情) 方法执行前后分别执行,可以阻止方法的执行。与AOP联盟定义的环绕通知类似,必须手动执行目标方法
afterThrowing:抛出异常通知(应用:包装异常信息) 方法抛出异常后执行,如果方法没有抛出异常,无法执行
after:最终通知(应用:清理现场) 方法执行完毕后执行,无论方法中是否出现异常
通过环绕通知,实现其他通知功能的方法:
环绕通知,必须手动执行目标方法
try{
//前置:before
//手动执行目标方法
//后置:afterRetruning
} catch(){
//抛出异常afterThrowing
} finally{
//最终 after
}
Maven的pom.xml文件需要添加jar包(除此之外还要导spring的包,详情见前面的文章):
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
AspectJ基于xml的实现方式:
切面类:public class MyAspect{
public void myBefore(JoinPoint joinpoint){
System.out.println("前置通知" + joinpoint.getSignature());
}
public void myAfterReturning(JoinPoint joinpoint,Object ret){
System.out.println("后置通知" + joinpoint.getSignature().getName() + "ret" + ret);
}
public Object myAround(ProceedingJoinPoint joinpoint) throws Throwable{
System.out.println("环绕前");
Object obj = joinpoint.proceed();
System.out.println("环绕后");
return obj;
}
public void myAfterThrowing(JoinPoint joinpoint, Throwable e){
System.out.println("抛出异常通知"+ e.getMessage());
}
public void myAfterFinal(JoinPoint joinpoint){
System.out.println("最终通知");
}
}
目标类:
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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- 创建目标类 -->
<bean id="userServiceImpl" class="net.seehope.springAOP.UserServiceImpl"></bean>
<!-- 创建切面类 -->
<bean id="myAspect" class="net.seehope.springAOP.MyAspect"></bean>
<!-- 3 aop编程
3.1 导入命名空间
3.2 使用 <aop:config>进行配置
proxy-target-class="true" 声明时使用cglib代理
<aop:pointcut> 切入点 ,从目标对象获得具体方法
<aop:advisor> 特殊的切面,只有一个通知 和 一个切入点
advice-ref 通知引用
pointcut-ref 切入点引用
3.3 切入点表达式
execution(* com.seehope.springAOP.*.*(..))
返回值任意 包 类名任意 方法名任意 参数任意
-->
<aop:config proxy-target-class="true">
<aop:aspect ref="myAspect">
<aop:pointcut expression="execution(* net.seehope.springAOP..*.*(..))" id="myPointCut"/>
<aop:after method="myAfterFinal" pointcut-ref="myPointCut"/>
<aop:before method="myBefore" pointcut-ref="myPointCut"/>
<aop:around method="myAround" pointcut-ref="myPointCut"/>
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e" />
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />
</aop:aspect>
</aop:config>测试类:
由测试结果可见,最终通知After的位置并没有出现在最后,反而是后置通知出现了在最后,不过这并不影响到我们的日常使用,日常开发中只用环绕通知即可,通过上文的try{}catch(){}finally{}的方式实现所有通知的功能
AsceptJ基于注解的实现方式:
切面类:
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 MyAspect {
@Pointcut("execution(* net.seehope.springAOP..*.*(..))")
private void myPointCut() {
}
@Before(value = "myPointCut()")
public void myBefore(JoinPoint joinpoint) {
System.out.println("前置通知:" + joinpoint.getSignature());
}
@AfterReturning(pointcut = "myPointCut()", returning = "ret")
public void myAfterReturning(JoinPoint joinPoint, Object ret) {
System.out.println("后置通知:" + joinPoint.getSignature().getName() + " ret: " + ret);
}
@Around("myPointCut()")
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前");
Object obj = joinPoint.proceed();
System.out.println("环绕后");
return obj;
}
@AfterThrowing(pointcut = "myPointCut()", throwing = "e")
public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("抛出异常之后通知" + e.getMessage());
}
@After("myPointCut()")
public void myAfterFinal(JoinPoint joinPoint) {
System.out.println("最终通知");
}
}xml配置文件:
与之前的测试结果相比会发现有些不同,至于为什么我也不知道
不过还是那句话,顺序不重要,毕竟能用环绕通知实现的事情,就不拜托其他的各位了
AspectJ的通知类型:
before:前置通知(应用:各种校验) 在方法执行前执行,如果通知抛出异常,阻止方法运行
afterReturning:后置通知(应用:常规数据处理) 方法正常返回后执行,如果方法中抛出异常,通知无法执行。因为必须在方法执行后才执行,所以可以获得方法的返回值。
around:环绕通知(应用:十分强大,可以做任何事情) 方法执行前后分别执行,可以阻止方法的执行。与AOP联盟定义的环绕通知类似,必须手动执行目标方法
afterThrowing:抛出异常通知(应用:包装异常信息) 方法抛出异常后执行,如果方法没有抛出异常,无法执行
after:最终通知(应用:清理现场) 方法执行完毕后执行,无论方法中是否出现异常
通过环绕通知,实现其他通知功能的方法:
环绕通知,必须手动执行目标方法
try{
//前置:before
//手动执行目标方法
//后置:afterRetruning
} catch(){
//抛出异常afterThrowing
} finally{
//最终 after
}
Maven的pom.xml文件需要添加jar包(除此之外还要导spring的包,详情见前面的文章):
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
AspectJ基于xml的实现方式:
切面类:public class MyAspect{
public void myBefore(JoinPoint joinpoint){
System.out.println("前置通知" + joinpoint.getSignature());
}
public void myAfterReturning(JoinPoint joinpoint,Object ret){
System.out.println("后置通知" + joinpoint.getSignature().getName() + "ret" + ret);
}
public Object myAround(ProceedingJoinPoint joinpoint) throws Throwable{
System.out.println("环绕前");
Object obj = joinpoint.proceed();
System.out.println("环绕后");
return obj;
}
public void myAfterThrowing(JoinPoint joinpoint, Throwable e){
System.out.println("抛出异常通知"+ e.getMessage());
}
public void myAfterFinal(JoinPoint joinpoint){
System.out.println("最终通知");
}
}
目标类:
public class UserServiceImpl implements UserService { @Override public void addUser() { // TODO Auto-generated method stub System.out.println("添加用户"); } @Override public User queryUserByXX() { // TODO Auto-generated method stub System.out.println("查找用户"); return null; } @Override public void update() { System.out.println("更新用户"); // TODO Auto-generated method stub } @Override public void delete() { System.out.println("删除用户"); // TODO Auto-generated method stub } }
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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- 创建目标类 -->
<bean id="userServiceImpl" class="net.seehope.springAOP.UserServiceImpl"></bean>
<!-- 创建切面类 -->
<bean id="myAspect" class="net.seehope.springAOP.MyAspect"></bean>
<!-- 3 aop编程
3.1 导入命名空间
3.2 使用 <aop:config>进行配置
proxy-target-class="true" 声明时使用cglib代理
<aop:pointcut> 切入点 ,从目标对象获得具体方法
<aop:advisor> 特殊的切面,只有一个通知 和 一个切入点
advice-ref 通知引用
pointcut-ref 切入点引用
3.3 切入点表达式
execution(* com.seehope.springAOP.*.*(..))
返回值任意 包 类名任意 方法名任意 参数任意
-->
<aop:config proxy-target-class="true">
<aop:aspect ref="myAspect">
<aop:pointcut expression="execution(* net.seehope.springAOP..*.*(..))" id="myPointCut"/>
<aop:after method="myAfterFinal" pointcut-ref="myPointCut"/>
<aop:before method="myBefore" pointcut-ref="myPointCut"/>
<aop:around method="myAround" pointcut-ref="myPointCut"/>
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e" />
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />
</aop:aspect>
</aop:config>测试类:
import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class PostTest { @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationCont 9dc1 ext("spring/applicationContext.xml"); UserServiceImpl userService = (UserServiceImpl) context.getBean("userServiceImpl"); userService.queryUserByXX(); } }测试结果:
由测试结果可见,最终通知After的位置并没有出现在最后,反而是后置通知出现了在最后,不过这并不影响到我们的日常使用,日常开发中只用环绕通知即可,通过上文的try{}catch(){}finally{}的方式实现所有通知的功能
AsceptJ基于注解的实现方式:
切面类:
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 MyAspect {
@Pointcut("execution(* net.seehope.springAOP..*.*(..))")
private void myPointCut() {
}
@Before(value = "myPointCut()")
public void myBefore(JoinPoint joinpoint) {
System.out.println("前置通知:" + joinpoint.getSignature());
}
@AfterReturning(pointcut = "myPointCut()", returning = "ret")
public void myAfterReturning(JoinPoint joinPoint, Object ret) {
System.out.println("后置通知:" + joinPoint.getSignature().getName() + " ret: " + ret);
}
@Around("myPointCut()")
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前");
Object obj = joinPoint.proceed();
System.out.println("环绕后");
return obj;
}
@AfterThrowing(pointcut = "myPointCut()", throwing = "e")
public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("抛出异常之后通知" + e.getMessage());
}
@After("myPointCut()")
public void myAfterFinal(JoinPoint joinPoint) {
System.out.println("最终通知");
}
}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" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <!-- 开启注释扫描 --> <context:component-scan base-package="net.seehope"/> <!-- 确定 aop注解生效 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!-- 创建目标类 --> <bean id="userServiceImpl" class="net.seehope.springAOP.UserServiceImpl"></bean> <!-- 创建切面类 --> <bean id="myAspect" class="net.seehope.springAOP.MyAspect"></bean> <aop:config proxy-target-class="true"> <aop:aspect ref="myAspect"></aop:aspect> </aop:config> </beans>测试类与目标之前的相同,不在单独显示,测试结果如下:
与之前的测试结果相比会发现有些不同,至于为什么我也不知道
不过还是那句话,顺序不重要,毕竟能用环绕通知实现的事情,就不拜托其他的各位了
相关文章推荐
- Spring学习_03_AOP在Spring中的两种实现方式
- Spring学习-22:Spring的AOP:基于AspectJ的XML配置方式开发
- spring框架的学习(四)——Spring的AOP的概述及AOP的操作(基于aspectj的xml方式)
- Spring学习4-面向切面(AOP)之aspectj注解方式
- JavaEE---------Spring之AOP实现两种方式
- Spring AOP的两种实现方式
- Spring4学习笔记-AOP(基于配置文件的方式)
- Spring学习4-面向切面(AOP)之aspectj注解方式
- ITCAST视频-Spring学习笔记(使用Spring的注解方式实现AOP的细节)
- spring实现AOP的两种方式以及实现动态代理方式
- spring实现AOP的两种方式以及实现动态代理方式
- 【学习】Spring 的 AOP :基于Annotation 的“零配置”方式
- Spring AOP AspectJ注解和XML配置两种实现(Maven构建)
- AOP的annotation实现方式是基于AspectJ的实现
- Spring AOP实现方式四之注入式AspectJ切面【附源码】
- Spring学习笔记(14)----使用Spring的注解方式实现AOP
- Spring4学习笔记-AOP(基于注解的方式)
- Spring的AOP分为注解和配置两种方式实现
- [学习小结]Spring_通知的那些事和基于配置文件的方式来配置AOP