基于注解的AOP配置

  • 一、环境搭建
  • 二、相关的注解
  • 三、基于注解的AOP配置步骤


一、环境搭建

1.1 在配置文件中导入context的名称空间,在资源包下建立bean.xml文件,导入aop和context相关的约束。

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

   <!--配置spring创建容器的时候要扫描的包-->
   <context:component-scan base-package="com.itheima"></context:component-scan>
   <!--配置spring开启注解AOP的支持-->
   <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

1.2 代码举例

//创建业务层接口
public interface IAccountService{
	void saveAccount();//模拟保存账户
	void updateAccount(int i);//模拟更新账户
	int deleteAccount();//删除账户
}

//业务层的实现类
@Service("accountService")
public class AccountServiceImpl implements IAccountService{
	public void saveAccount(){
		System.out.pringln("执行了保存");
	}
	public void updateAccount(int i){
		System.out.pringln("执行了更新" + i);
	}
	public int deleteAccount(){
		System.out.pringln("执行了删除");
		return 0;
	}
}

//创建一个记录日志的工具类,他里面提供了公共代码
@Component("logger")
@Aspect//表示当前类是一个切面类
public class Logger{
	@Printcut("execution(*com.itheima.service.impl.*.*(..))")//配置切入点表达式
	privete void pt1(){}

	@Before("pt1()")//配置前置通知的配置切入点表达式
	public void beforePrintLog(){
		System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。")
	}

	@AfterReturning("pt1()")//配置后置通知的配置切入点表达式
	public void afterReturningPrintLog(){
		System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。")
	}
	
	@AfterThrowing("pt1()")//配置异常通知的切入点表达式
	public void AfterThrowingPrintLog(){
		System.out.println("异常通知Logger类中的AfterThrowingPrintLog方法开始记录日志了。。。")
	}

	@After("pt1()")//配置最终通知的切入点表达式
	public void afterPrintLog(){
		System.out.println("最终通知Logger类中的beforePrintLog方法开始记录日志了。。。")
	}
}

//在切入点方法执行之前执行前置通知的方法,在如果切入点方法正常执行之后执行后置通知,如果切入点方法出现异常,则不执行后置通知,直接执行异常通知,不管程序是否正常执行,最后的都执行最终通知。

/**
* 环绕通知
* 问题:当我们配置环绕通知之后,切入点方法没有执行,而是通知方法执行了。
* 分析:通过对比动态代理的环绕通知代码,发现动态代理的环绕通知有明确的切入点方法调用,而我们的代码中没有。
*解决:Spring框架为我们提供一个接口,ProceedingJoinPoint,该方法有一个接口proceed(),此方法就相当于明确调入切入点方法,该接口可以作为环绕通知的方法参数,在程序执行的时候,spring框架会为我们提供该接口的实现类供我们使用,。
*
*spring中的环绕通知:它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。
*
*/
@Around("pt1()")//配置环绕通知的代码。
public Object aroundPringLog(ProceedingJoinPoint pjp){
	Object rtValue = null;
	try{
		Object[] args = pjp.getArgs();//得到方法执行所需的的参数
		System.out.println("Logger类中的arroundPringLog方法开始记录日志了。。前置");
		rtVlalue = pjp.proceed(args);//明确调入业务层方法(切入点方法)
		System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。后置");
		return rtVlue;
	}catch(Throwable t){
		System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常")
		throw new RuntimeException(t);
	}finally{
		System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终")
	}
}

二、相关的注解

2.1 @Aspect

作用:把当前类申明为切面类

2.2 @Before

作用:把当前方法看成前置通知。
属性:value:用于指定切入点表达式,还可以指定切入点表达式的引用。

2.3@AfterReturning

作用:把当前方法看成后置通知。
属性:value用于指定切入点表达式,还可以指定,切入点表达式的引用。

2.4@AfterThrowing

作用:把当前方法看成是异常通知
属性:value:同上

2.5@After

作用:把当前方法看成是最终通知。
属性:value:同上

2.6@Around

作用:把当前方法看成是环绕通知。
属性:value:同上

2.7@Pointcut

作用:指定切入点表达式。
属性:value:指定表达式的内容。

三、基于注解的AOP配置步骤

1、准备必要的代码和jar包。
2.在配置文件中导入context的名称空间。
3.把资源使用注解配置。
4.在配置文件中指定spring要扫描的包。
5.把通知类也使用注解配置。
6.在通知类都会那个使用@Aspect注解为切面类。
7.在spring配置文件中开启spring对注解的AOP的支持。