使用SpringAOP
AOP是什么?
Aspect Oriented Programming(面向切面编程):将有共同处理的业务,从传统的业务中抽离出来单独的封装,通过装配(注解)的方式作用于系统。在不修改系统业务逻辑的前提下给系统追加功能。
AOP三要素
1.切面:追加什么?单独封装的切面代码。
2.通知:什么时候追加?前置,后置,异常,最终,环绕。
3.切入点:切谁?方法/类型/bean限定表达式。
通知类型
Spring提供了五种通知类型:
1.前置通知(@Before):在连接点前执行。
2.后置通知(@AfterReturnning):在连接点后正常返回执行(ps:如果方法抛出异常则不会执行)。
3.异常通知(@AfterThrowing):在连接点抛出异常之后执行。
4.最终通知(@After):在连接点执行完成后执行。不管连接点是正常执行完成还是抛出异常后,都会执 行。
5.环绕通知(@Around):在连接点前后执行,是一个强大的通知类型。可以决定方法是否继续执行。通过调用ProceedingJoinPoint的proceed()。
执行顺序:首先执行的是环绕通知中调用proceed()前的代码,其次调用前置通知,再执行被切方法(ps:如果这时方法抛出异常回去执行异常通知),接着继续执行环绕通知中调用proceed()后的代码,然后执行最终通知,最后执行后置通知。
切点表达式:
1.匹配方法签名:execution(修饰词 返回值 方法名(参数) 抛出异常)
execution(* com.xxx.service.*(..)):匹配指定包中的所有方法。
execution(public * com.xxx.service.UserService.*(..)):匹配指定类的所有public方法。
execution(* com.xxx.service.UserService.crtUser(..)):匹配UserService类中的crtUser方法。
2.匹配类型签名:
within(com.xxx.service.*):匹配指定包中所有的方法,但不包括子包。
within(com.xxx.service..*):匹配指定包及其子包中所有方法。
within(com.xxx.service.UserService):匹配指定类中所有方法。
within(com.xxx.dao.UserDao+):匹配指定接口所有的实现类中的方法。
3.匹配Bean名字
bean(*Service):匹配名字以Service结尾的Bean中的所有方法。
4.组合使用表达式:
bean(*Service || *ServiceImpl):匹配以Service或ServiceImpl结尾的bean。
bean(*Service) && within(com.xxx.service):匹配名字已Service结尾,并且在包com.xxx.service中的bean。
动态代理:
AOP底层实现是通过动态代理技术来实现的,所谓的动态代理就是动态创建类的技术。动态代理技术有两种:1.基于接口技术,实现接口重写了接口中的方法。2.基于类的技术,继承类后重写类的方法。第一种是java内部的反射机制生成字节码并生成对象来实现的,第二种是使用cglib产生代理,而底层是借助sm来实现的,这个asm就是一个java字节码操纵框架,他能用来动态生成类增强类的功能。(由于我目前对动态代理了解不深就先介绍到这里)
简单实现:
1.在spring配置文件中添加配置如下
<!-- 扫面指定的包让spring管理带有特定注解的对像 --> <context:component-scan base-package="com.xxx.service"/> <!-- 启动aop注解 --> <aop:aspectj-autoproxy />
2.切面类,也就是需要追加的代码以及代码的追加方式
package com.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import java.util.Map; /** * Created by hang on 2018/3/12. */ @Component @Aspect//表示下面的代码是切面组件 public class AspectDemo { @Before("execution(* com.Service.EntryService.addEntry(..))") public void testAop(){ System.out.println("AOP实现注入"); System.out.println("在执行方法前"); } @AfterReturning("execution(* com.Service.EntryService.addEntry(..))") public void testAop2(){ System.out.println("AOP实现注入"); System.out.println("在执行方法后"); } @After("execution(* com.Service.EntryService.addEntry(..))") public void testAop4(){ System.out.println("AOP实现注入"); System.out.println("After执行"); } @Around("execution(* com.Service.EntryService.addEntry(..))") public Map<String,String> testAop3(ProceedingJoinPoint pjp) throws Throwable { System.out.println("AOP实现注入"); System.out.println("环绕前执行"); Map map = (Map) pjp.proceed(); System.out.println("AOP实现注入"); System.out.println("环绕后执行"); return map; } }
@Service public class EntryService { public void add(){ System.out.println("UserService add()"); } public boolean delete(){ System.out.println("UserService delete()"); return true; } public void edit(){ System.out.println("UserService edit()"); int i = 5/0; } }