2019-06-12
面向切面编程(AOP):应用程序在运行时,由Spring动态地将切面织入到应用程序指定的业务方法中。
切面(Aspect):是把在众多业务中普遍存在的共有代码抽取出来封装为切面类集中管理,在程序运行时,由Spring容器运用动态代理技术在指定业务中自动织入这些切面。
什么是动态代理
AOP技术建立在动态代理机制之上。系统运行时,Spring会动态创建一个代理对象(Proxy)供使用者调用,该代理对象已经将切面织入到目标对象的业务方法中,从而使切面的功能与目标对象的业务功能同时得以执行。
调用者直接调用的其实是Spring动态生成的代理对象,再由代理对象调用目标对象完成原始的业务处理,而代理对象则已经将切面与业务逻辑方法进行了合成。
使用注解方式实现AOP
设计切面类,编写切面通知
@Component
@Aspect
public class LogAspect {
//注解里使用的变量只能是final String类型
public static final String EDP = "execution(* com.controller.LoginController.*(..))";
@Before(EDP) //前置通知
public void beforeAdvice(JoinPoint joinpoint) {}
@AfterReturning(EDP) //后置通知
public void afterReturningAdvice(JoinPoint joinpoint) {}
@AfterThrowing(pointcut = EDP, throwing = "e") //异常通知
public void afterThrowingAdvice(JoinPoint joinpoint, Exception e) {}
@After(EDP) //最终通知
public void afterAdvice(JoinPoint joinpoint) {}
@Around(EDP) //环绕通知
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
Object result = pjp.proceed();// 传递给连接点对象进行接力处理
return result;
}
}
1.什么是通知
通知(Advice)是切面的具体功能,通常是切面类中的方法。以目标方法连接点为参照,根据这个通知欲切入到目标方法的位置不同可分为:
- 前置通知(Before):是指在某个连接点方法之前执行的通知。如果这个通知不抛出异常,那么该连接点就一定会被执行。常用于权限管理。
- 后置通知(AfterReturning):是指某个连接点方法正常完成(没有抛出异常)后执行的通知。常用于IO流关闭、临时文件删除等。
- 异常通知(AfterThrowing):是指在连接点方法抛出异常退出时执行的通知。常用于异常处理、日志记录等。
- 最终通知(After):是指无论在任何情况下连接点方法退出时执行的通知,也就是说无论连接点方法正常退出还是抛出异常退出都会执行此通知。类似于异常处理机制中finally块的作用,常用于释放资源。
- 环绕通知(Around):是指包围连接点方法的通知。这种通知功能非常强大,可以替代前面任意一种通知的功能。常用于日志记录、事务处理。
2.AOP注解说明
- @Aspect:使用@Aspect注解的类,Spring会当作切面类处理。
- @Before:前置通知
- @AfterReturning:后置通知
- @AfterThrowing:异常通知
- 必须使用@AfterThrowing(pointcut = 连接点,throwing = "e")的形式,否则会出现”error at ::0 formal unbound in pointcutd”错误
- @After:最终通知
- @Around:环绕通知
- @Pointcut:定义切入点表达式,需要同时定义一个切入点方法,返回值为void且方法体为空
3.切入点表达式
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?
name-pattern(param-pattern) throws-pattern?)
说明:
- 访问类型模式(modifiers-pattern):方法的访问类型,如public表示匹配所有公用方法,此模式通常可省略不写,除非有特定需求。
- 返回值类型模式(ret-type-pattern):方法的返回值类型,设置为
*表示匹配任意的返回值类型。 - 类型名称模式(declaring-type-pattern):表示匹配的包或类的名称规则,"
包路径.*"表示指定包下的所有类均予以匹配,"包路径..*"则表示指定包及其子包下的所有类均予以匹配,"包路径.类名"表示指定的类予以匹配。 - 名字模式(name-pattern):匹配方法名,
*表示匹配所有方法,set*表示所有方法名以set开头的方法。
参数模式(param-pattern): ()表示匹配不接受任何参数的方法,(..)表示匹配接受任意数量参数的方法,(*)表示匹配接受一个任何类型的参数的方法, (*,String)则表示匹配接受两个参数的方法,第一个参数可以是任意类型,而第二个参数必须是String类型。 - 异常模式(throws-pattern):抛出何种类型的异常,如RuntimeException表示匹配抛出RuntimeException异常的方法,此模式通常可省略不写,除非有特定的需求。
| 切入点正则表达式 | 功 能 描 述 |
|---|---|
| execution(public * *(..)) | 匹配所有公有方法 |
| execution(* set*(..)) | 匹配所有以“set”开头的方法 |
| execution(* com.action.UserController.*(..)) | 匹配UserController类的所有方法 |
| execution(* com.action..(..)) | 匹配com.action包下所有类的所有方法 |
| execution(* com.action...(..)) | 匹配com.action包及子包下所有类的所有方法 |
修改Spring配置文件
启动基于注解的AspectJ支持
<aop:aspectj-autoproxy />