先来介绍一下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文件配置的方式要简单一些。