spring中的AOP即面向切面编程:它是在不改变源代码的前提下,对类中的方法进行增强,分为前置,后置,环绕,异常,全篇分为三个方面,aop开发基础讲解,切面类的传参和值的返回,以及使用aop做缓存的一些思路
切面基础讲解
创建项目前:引入aop
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
创建Person:
@Component public class Person { public void eat(){ System.out.println("我要开始吃饭了"); } }
创建切面类:
第一个:前置增强:注意声明切面位置指定是类中的方法
@Component @Aspect @EnableAspectJAutoProxy public class PersonAspect {
private static final String PERSON_POINT = "execution(* com.gwq.springmybatis.springmybatis.pojo.Person.eat(..))"; @Before(PERSON_POINT) public void before(){ System.out.println("请先喝汤"); } }
第二个:增加后置增强
@Component @Aspect @EnableAspectJAutoProxy public class PersonAspect { private static final String PERSON_POINT = "execution(* com.gwq.springmybatis.springmybatis.pojo.Person.eat(..))"; @Before(PERSON_POINT) public void before(){ System.out.println("请先喝汤"); } @After(PERSON_POINT) public void after(){ System.out.println("睡觉了"); } }
第三个:环绕增强
@Component @Aspect @EnableAspectJAutoProxy public class PersonAspect { private static final String PERSON_POINT = "execution(* com.gwq.springmybatis.springmybatis.pojo.Person.eat(..))"; //@Before(PERSON_POINT) public void before(){ System.out.println("请先喝汤"); } // @After(PERSON_POINT) public void after(){ System.out.println("睡觉了"); } @Around(PERSON_POINT) public void around(ProceedingJoinPoint joinPoint) throws Throwable { before(); joinPoint.proceed(); after(); } }
第四个:异常
先在被切面的类上设置异常
@Component public class Person { public void eat(){ System.out.println("我要开始吃饭了"); int num = 10/0; } }
在切面类中捕获异常
@Component @Aspect @EnableAspectJAutoProxy public class PersonAspect { private static final String PERSON_POINT = "execution(* com.gwq.springmybatis.springmybatis.pojo.Person.eat(..))"; //@Before(PERSON_POINT) public void before(){ System.out.println("请先喝汤"); } // @After(PERSON_POINT) public void after(){ System.out.println("睡觉了"); } @Around(PERSON_POINT) public void around(ProceedingJoinPoint joinPoint) throws Throwable { before(); joinPoint.proceed(); after(); } //throwing = "aw" 和Throwable aw 俩个变量名要保持一致 @AfterThrowing(value =PERSON_POINT,throwing = "aw") public void exc(Throwable aw){ System.out.println("出错信息"+aw.getMessage()); } }
测试:
前置增强测试
@SpringBootTest @RunWith(SpringRunner.class) public class ApplicationTest { @Autowired private Person person; @Test public void aopTest(){ person.eat(); } }
结果:在执行自身方法,被拦截,先执行切面类中的方法
后置增强测试类同上,结果:
环绕增强测试结果
异常测试展示:
在执行类中的方法时,在切面中返回方法返回值
问题出现:在类中方法设置返回值
@Component public class Person { public String eat(){ System.out.println("我要开始吃饭了"); return "吃肉了"; } }
增强类
@Component @Aspect @EnableAspectJAutoProxy public class PersonAspect { private static final String PERSON_POINT = "execution(* com.gwq.springmybatis.springmybatis.pojo.Person.eat(..))"; //@Before(PERSON_POINT) public void before(){ System.out.println("请先喝汤"); } // @After(PERSON_POINT) public void after(){ System.out.println("睡觉了"); } @Around(PERSON_POINT) public void around(ProceedingJoinPoint joinPoint) throws Throwable { before(); joinPoint.proceed(); after(); } }
测试类调用:输出方法中的值
@SpringBootTest @RunWith(SpringRunner.class) public class ApplicationTest { @Autowired private Person person; @Test public void aopTest(){ String food = person.eat(); System.out.println(food); } }
问题解决:输出类中的返回值
对上面的切面做修改
@Around(PERSON_POINT) public Object around(ProceedingJoinPoint joinPoint) throws Throwable { before(); Object proceed = joinPoint.proceed(); after(); return proceed; }
查看测试结果:
在切面类中,获取执行类的方法参数
在执行类中添加参数
在切面类获取参数
测试结果
输出了鸡肉,说明获取了参数返回值
使用Spring AOP来实现缓存的使用:逻辑是在以setvice的实现类座位目标类,在切面类中使用环绕方法,获取参数,先从缓存获取,如果缓存有,就直接返回值,缓存没有就从数据库获取然后删除缓存。