先来介绍一下AOP操作中的几个术语:
1、连接点:指类里面可以被增强的方法
2、切入点:指实际被增强的方法
3、通知:指实际增强的逻辑部分
4、切面:把通知应用到切入点的过程
Spring框架一般都是基于AspectJ实现AOP操作
1、导入相关jar包:
2、进行通知的配置:
创建bean1.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启注解扫描-->
<context:component-scan base-package="AOPDemo"></context:component-scan>
<!-- 开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
3、创建被增强类User,增加注解@Componet
package AOPDemo;
import org.springframework.stereotype.Component;
/**
* 用于 用注解方式进行AOP操作
*/
@Component
public class User {
public void add(){
System.out.println("hhh");
}
}
4、创建增强类UserProxy
先增加注解@Componet,再在下方增加注解@Aspect
通知类型的注解:@加上注解类型(注解表达式)
例如:@Before(value = "execution(* AOPDemo.User.add(..))")
package AOPDemo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect //表示生产代理对象
public class UserProxy {
/**
* 前置通知
* 作为通知,在User类的add()之前调用
*/
@Before(value = "execution(* AOPDemo.User.add(..))")
public void before(){
System.out.println("before....");
}
/**
* 最终通知
*/
@After(value = "execution(* AOPDemo.User.add(..))")
public void after(){
System.out.println("after....");
}
/**
* 后置通知(返回通知)
*/
@AfterReturning(value = "execution(* AOPDemo.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning....");
}
/**
* 异常通知
*/
@AfterThrowing(value = "execution(* AOPDemo.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing....");
}
/**
* 环绕通知 ,会在被增强的方法前后都执行
*/
@Around(value = "execution(* AOPDemo.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("around before....");
//被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println("around after....");
}
}
在这里补充一下知识:通知有多种类型:
在增强方法中,我把它们全部测试一遍,看看效果如何
也可以用切入点抽取把相同的切入点表达式抽取,可以简单一点
/**
* 相同切入点抽取的做法
*/
@Component
@Aspect //表示生产代理对象
class UserProxy1{
//相同切入点抽取
@Pointcut(value = "execution(* AOPDemo.User.add(..))")
public void pointdemo(){
}
/**
* 前置通知
* 作为通知,在User类的add()之前调用
*/
@Before(value = "pointdemo()")
public void before(){
System.out.println("before....");
}
/**
* 最终通知
*/
@After(value = "pointdemo()")
public void after(){
System.out.println("after....");
}
/**
* 后置通知(返回通知)
*/
@AfterReturning(value = "pointdemo()")
public void afterReturning(){
System.out.println("afterReturning....");
}
/**
* 异常通知
*/
@AfterThrowing(value = "pointdemo()")
public void afterThrowing(){
System.out.println("afterThrowing....");
}
/**
* 环绕通知 ,会在被增强的方法前后都执行
*/
@Around(value = "pointdemo()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("around before....");
//被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println("around after....");
}
}
5、写一个测试方法测试一下
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user",User.class);
user.add();
}
测试结果:
可以看到,异常通知并没有出现,是因为代码中没有异常,那我们手动添加一下异常,看看效果
在add方法中加个异常10/0
运行一下:
可以看出,除了异常通知之外,还有after(后置)通知也执行了。
以上就是使用注解方式进行AOP操作的过程了,比XML文件配置的方式要简单一些。