Spring基础学习(九)——基于AspectJ的两种AOP实现方式

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


 与之前的测试结果相比会发现有些不同,至于为什么我也不知道尴尬不过还是那句话,顺序不重要,毕竟能用环绕通知实现的事情,就不拜托其他的各位了


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值