一,相关名词
切面(Aspect):一个横切功能的模块化,这个功能可能会横切多个对象(业务),比如:aMethod()方法就是一个"切面",它横切到多个业务中
切入点(Pointcut):可以插入 "横切逻辑(如aMethod())"的方法。比如:"调用add()"就是一个切点。
通知:
前置通知(Before Advice):在切入点add()方法执行之前,插入的通知。
后置通知(After Returning Advice):在切入点add()方法执行完毕之后,插入的通知
异常通知(After Throwing Advice):在切入点add()方法抛出异常时,插入的通知
最终通知(After FinallyAdvice):当切入点add()方法执行完毕时,插入的通知(不论是正常返回还是异常退出)
环绕通知(Around Advice):可以贯穿切入点add()方法执行的整个过程。
二,通知
1,我们想把一个普通的类变成一个特定功能的类。有三种方法:
继承类
实现接口
加注解
配置
2,把一个普通的类 变成 "通知",
2.1,通过让类实现接口来实现
通知类型 需要实现的接口 接口中的方法 执行时机
前置通知 org.springframework.aop.MethodBeforeAdvice before() 目标方法执行前
后置通知 org.springframework.aop.AfterReturningAdvice afterReturning() 目标方法执行后
异常通知 org.springframework.aop.ThrowsAdvice 无 目标方法发生异常时
环绕通知 org.aopalliance.intercept.MethodInterceptor invoke() 拦截对目标方法调用,即调用目标方法的整个过程
2.2, 以后置通知为例:
实现逻辑(三步):
A,需要通知类 ----> 普通类实现接口
B,业务类,业务方法 ------> StudentServiceImpl中的addStudent();
C,配置:
将业务类,通知 纳入springIOC容器
定义切入点(一端),定义通知类(另一类),通过pointcut-ref将两端连接起来
代码实现:
业务类:
public class StudentServiceImpl implements StudentService{
@Autowried
private StudentDao studentDao;
public int addStudent(Student student){
int result = studentDao.insert(student);
System.out.println("添加学生");
return result;
}
}
通知类:
public class LogAfter implements AfterReturningAdvice{
@Override
public void afterReturning(Object returnValue,Method mehtod,Object[] args,Object target)throws Throwable{
Sysout.out.println(" 前置通知 ");
//我们还可以拿到目标对象的一些属性。对于studentService.addStudent(); 来说,studentService就是目标对象
Sysout.println("目标对象:" + target + "调用的方法名:"+method.getName()+"方法参数的个数:"+args.length+",方法的返回值:"+ returnValue);
}
}
配置:application.xml
//将业务类纳入springIOC容器
<bean id = "studentService" class = "org.yaming.service.StudentService">
<property name = "stuentDao" ref = "studentDao"></property>
</bean>
//将通知纳入springIOC容器
<bean id = "LogAfter" class = "org.yaming.aop.LogAfter"></bean>
<aop:config>
//切入点(连接线的一端:业务类的具体方法)
<aop:pointcut expression = "execution(public * org.yaming.service.StudentServiceImpl.addStudent(..))" id = "pointcut"/>
//连接线的另一端:通知类
<aop:advisor advice-ref = "LogAfter" pointcut-ref = "pointcut"/>
</aop:config>
3,通过注解来实现
3.1,代码示例:
@Aspect //声明该类是一个通知
public class LogBeforeAnnotation(){
@Before("execution(public * addStudent(..))")
public void myBefore(){
System.out.println("注解形式---前置通知")
}
@AfterReturning("execution(public * addStudent(..))")
public void myAfter(){
System.out.println("注解形式---后置通知")
}
}
开启注解对AOP的支持: <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
3.2,通过注解形式实现的aop,如果想获取目标对象的一些参数,需要使用一个对象:JoinPoint
public class LogBeforeAnnotation(){
@Before("execution(public * addStudent(..))")
public void myBefore(JointPoint jp){
System.out.println("注解形式---前置通知");
System.out.println("目标对象:" + jp.getTarget()+",方法名:"+jp.getSignature().getName()+",参数列表:"+Arrays.toString(jp.getArgs()));
}
@AfterReturning("execution(public * addStudent(..))" , returning = "returningValue")
public void myAfter(JoinPoint jp,Object returningValue){
System.out.println("注解形式---后置通知");
System.out.println("目标对象:" + jp.getTarget()+",方法名:"+jp.getSignature().getName()+",参数列表:"+Arrays.toString(jp.getArgs()) + ",返回值:"+returningValue);
}
}