您的位置:首页 > 编程语言 > ASP

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("最终通知");
}
}


目标类:
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>
测试类与目标之前的相同,不在单独显示,测试结果如下:



 与之前的测试结果相比会发现有些不同,至于为什么我也不知道

不过还是那句话,顺序不重要,毕竟能用环绕通知实现的事情,就不拜托其他的各位了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: