前置技能:
Java、JDBC、Spring IOC快速入门 、 Spring IOC 注解方式注入 、Spring AOP 注解方式实现
什么是AOP:
面向切口编程(Aspect Oriented Programming),AOP是OOP的延续,是Spring框架的一个重要内容。
AOP利用称为"横切"的技术,剖解开封装的对象内部,把多个类的公共行为封装到一个可重用模块中,便于减少重复代码,降低模块之间的耦合度,AOP符合开闭原则,提高了代码的可拓展性。
AOP概念名词:
通知(advice)
在已存在的业务方法的前、后、异常、最终处加入的方法。
切面(aspect)
通知advice
方法所在的类,一个 aspect
类中可以有多个通知方法。
连接点(joinPoint)
已存在的业务方法。
切入点(pointCut)
joinPoint
的集合。(为要添加advice
的方法划定范围。)
目标对象(target)``
joinPoint
方法所在的对象。
织入(Weave)``
把advice
方法放在joinPoint
的前、后、异常、最终处。(只有织入后,advice
才会有效。)
ps.温馨提示:你可以先看完Getting Started,再回来理解这些。
Getting Started
0、目录
aspect
切面类
service
服务层
2、连接点 类
public interface IService {
String update(String msg);
}
这里的业务方法就是连接点 joinPoint
,我们要在它的前后插入其他的方法(通知 advice
)。
//这里我们没有写Service注解,当然你可以通过注解方式纳入容器
public class IServiceImpl implements IService {
@Override
public String update(int uid, String msg) {
System.out.println("serviceimpl运行了");
return "更新了数据:"+msg;
}
}
3、切面类纳入容器
我们在切面类Aspect
写了一个前置通知,但并没有做任何注解。
public class DemoAspect {
public void myBefore() {
System.out.println("——————前置通知————");
}
public void myafterAdvice(JoinPoint point,Object obj) {
System.out.println("——————返回通知————");
Object[] args=point.getArgs();
String methodName=point.getSignature().getName();
Object targetObj=point.getTarget();
String targetClassName=point.getClass().getName();
System.out.println(targetClassName+"+"+methodName+"+"+Arrays.asList(args));
}
public void myafterException(JoinPoint point,Exception e) {
System.out.println("——————异常通知————"+e.getMessage());
}
public void myafeter(JoinPoint point) {
System.out.println("——————最终通知————"+point.getSignature().getName());
}
4、配置xml
配置xml虽然比写注解麻烦,但更方便修改和扩展。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 启动基本的注解Controller,Service,Repository,Component,Autowired,Resource,Qulifer -->
<context:component-scan base-package="com.aop"></context:component-scan>
<!-- 开启spring-aop的注解识别-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 到这里都和注解方式实现一样-->
<!-- 1、将切面类纳入容器-->
<bean id="myAspect" class="com.aop.aspect.DemoAspect"></bean>
<!-- 2、将service实现类纳入容器-->
<bean id="myService" class="com.aop.service.IServiceImpl"></bean>
<!-- 3、写aop配置-->
<aop:config>
<!-- 3.1、切面类 ref:指定切面类的标签id-->
<aop:aspect ref="myAspect">
<!-- 3.2、切入点 id:唯一 expression:切入点范围 -->
<aop:pointcut id="myPointCut" expression="execution(* com.aop.service.*.*(..))"/>
<!-- 3.3、配置通知方法-->
<!-- 3.3.1、前置通知 method:方法名 pointcut-ref:切入点的标签id -->
<aop:before method="myBefore" pointcut-ref="myPointCut"/>
<!-- 3.3.2、返回通知 method:方法名 returning:返回对象的属性名 pointcut-ref:切入点的标签id -->
<aop:after-returning method="myBeforeReturning " pointcut-ref="myPointCut" returning="obj"/>
<!-- 3.3.3、异常通知 method:方法名 throwing:异常对象的属性名 pointcut-ref:切入点的标签id -->
<aop:after-throwing method="myBeforeThrowing " throwing="e" pointcut-ref="myPointCut"/>
<!-- 3.3.4、最终通知 method:方法名 pointcut-ref:切入点的标签id -->
<aop:after method="myAfter" pointcut-ref="myPointCut"/>
<!-- 3.3.5、环绕通知 method:环绕通知的方法名 throwing:异常对象的属性名 -->
<aop:around method="myAround" pointcut-ref="myPointCut"/>
</aop:aspect>
</aop:config>
</beans>
5、测试
多个单项通知的运行结果:
环绕通知的运行结果: