目录
- 前言
- 编程范式主要有以下几类
- aop注解
- 用法
前言
spring提供两个核心功能,一个是Ioc(控制反转),另一个是Aop(面向切面编程),Ioc有助于应用对象之间的解耦,AOP则可以实现横切关注点(如日志、安全、缓存、重复提交和事务管理)与他们所影响的对象之间的解耦。
编程范式主要有以下几类
- AOP(Aspect Oriented Programming)面向切面编程
- OOP(Object Oriented Programming)面向对象编程
- POP(procedure oriented programming)面向过程编程
- FP(Functional Programming)面向函数编程
aop注解
AOP主要包含了通知、切点和连接点灯术语,介绍如下:
- 通知(Advice)
通知定义了切面是什么以及何时被调用,何时调用包含以下几种:
- Before 在方法被调用之前调用通知
- After 在方法完成之后调用通知,无论方法执行是否成功
- After-returning 在方法成功执行之后调用通知
- After-throwing 在方法抛出异常后调用通知
- Around 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为
- 切点(PointCut)
通知定义了切面是什么和何时被调用,切点定义了何处被调用,切点的定义会匹配通知所要织入的一个或多个连接点,我们通常使用明确的类的方法名称来指定这些切点,或是利用正则表达式定义匹配的类和方法名称来指定这些切点。
- 连接点(JoinPoint)
连接点是在应用执行过程中能够插入切面的一个点,这个点可以是调用方法时,抛出异常时,甚至是修改一个字段时,切面代码可以利用这些连接点插入到应用的正常流程中,并添加新的行为,如日志、安全、事务、缓存等。
(被拦截到的点,因为spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接带你还可以是字段或者构造器。)
-
@Aspect
: 切面,由通知和切入点共同组成,这个注解标注在类上表示为一个切面。 -
@Joinpoint
: 连接点,被AOP拦截的类或者方法,在前置通知中有介绍使用@Joinpoint
获取类名、方法、请求参数。 -
Advice
: 通知的几种类型 -
@Before
: 前置通知,在某切入点@Pointcut
之前的通知 -
@After
: 后置通知,在某切入点@Pointcut
之后的通知无论成功或者异常。 -
@AfterReturning
: 返回后通知,方法执行return之后,可以对返回的数据做加工处理。 -
@Around
: 环绕通知,在方法的调用前、后执行。 -
@AfterThrowing
: 抛出异常通知,程序出错跑出异常会执行该通知方法。 -
@Pointcut
: 切入点,从哪里开始。例如从某个包开始或者某个包下的某个类等。
用法
AOP在spring中有两种配置方式,一是xml配置的方式,二是自动注解的模式。
自动注解AOP
声明切面类,包含注解@Aspect以及何时执行通知(Advice)
package com.ganji.demo.service.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Service;
/**
* Created by admin on 2015/9/2.
*/
@Aspect
@Service
public class XmlAopDemoUserLog {
// 配置切点 及要传的参数
@Pointcut("execution(* com.ganji.demo.service.user.UserService.GetDemoUser(..)) && args(id)")
public void pointCut(int id)
{
}
// 配置连接点 方法开始执行时通知
@Before("pointCut(id)")
public void beforeLog(int id) {
System.out.println("开始执行前置通知 日志记录:"+id);
}
// 方法执行完后通知
@After("pointCut(id)")
public void afterLog(int id) {
System.out.println("开始执行后置通知 日志记录:"+id);
}
// 执行成功后通知
@AfterReturning("pointCut(id)")
public void afterReturningLog(int id) {
System.out.println("方法成功执行后通知 日志记录:"+id);
}
// 抛出异常后通知
@AfterThrowing("pointCut(id)")
public void afterThrowingLog(int id) {
System.out.println("方法抛出异常后执行通知 日志记录"+id);
}
// 环绕通知
@Around("pointCut(id)")
public Object aroundLog(ProceedingJoinPoint joinpoint,int id) {
Object result = null;
try {
System.out.println("环绕通知开始 日志记录"+id);
long start = System.currentTimeMillis();
//有返回参数 则需返回值
result = joinpoint.proceed();
long end = System.currentTimeMillis();
System.out.println("总共执行时长" + (end - start) + " 毫秒");
System.out.println("环绕通知结束 日志记录");
} catch (Throwable t) {
System.out.println("出现错误");
}
return result;
}
}
以上即实现aop。
spring AOP之proceedingjoinpoint和joinpoint区别
import org.aspectj.lang.reflect.SourceLocation;
public interface JoinPoint {
String toString(); //连接点所在位置的相关信息
String toShortString(); //连接点所在位置的简短相关信息
String toLongString(); //连接点所在位置的全部相关信息
Object getThis(); //返回AOP代理对象,也就是com.sun.proxy.$Proxy18
Object getTarget(); //返回目标对象,一般我们都需要它或者(也就是定义方法的接口或类,为什么会是接口呢?这主要是在目标对象本身是动态代理的情况下,例如Mapper。所以返回的是定义方法的对象如aoptest.daoimpl.GoodDaoImpl或com.b.base.BaseMapper<T, E, PK>)
Object[] getArgs(); //返回被通知方法参数列表
Signature getSignature(); //返回当前连接点签名 其getName()方法返回方法的FQN,如void aoptest.dao.GoodDao.delete()或com.b.base.BaseMapper.insert(T)(需要注意的是,很多时候我们定义了子类继承父类的时候,我们希望拿到基于子类的FQN,这直接可拿不到,要依赖于AopUtils.getTargetClass(point.getTarget())获取原始代理对象,下面会详细讲解)
SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置
String getKind(); //连接点类型
StaticPart getStaticPart(); //返回连接点静态部分
}
public interface ProceedingJoinPoint extends JoinPoint {
public Object proceed() throws Throwable;
public Object proceed(Object[] args) throws Throwable;
}
方法名 | 功能 |
---|---|
Signature getSignature(); | 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息 |
Object[] getArgs(); | 获取传入目标方法的参数对象 |
Object getTarget(); | 获取被代理的对象 |
Object getThis(); | 获取代理对象 |
proceedingjoinpoint和joinpoint的区别
JoinPoint的用法
ProceedingJoinPoint 执行procceed方法的作用
1、环绕通知ProceedingJoinPoint执行proceed方法的作用是让目标方法执行,这也是环绕通知和前置、后置通知方法的一个最大区别。
2、简单理解,环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。