spring-AOP
AOP(Aspect Oriented Programming),即面向切面编程。
目录
AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过 OOP 允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在 OOP 设计中,它导致了大量代码的重复,而不利于各个模块的重用。
OOP 面向对象,允许开发者定义纵向的关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。
AOP 技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名 为" Aspect ",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
AOP 的特性
切面(Aspect)
被抽取的公共模块,可能会横切多个对象。 在Spring AOP中,切面可以使用通用类或者在普通类中以@AspectJ注解来实现。
连接点(Join point)
指方法在Spring AOP中,一个连接点总是代表一个方法的执行。
通知(Advice)
在切面的某个特定的连接点(Join point)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
切入点(Pointcut)
切入点是指我们要对哪些Join point进行拦截的定义。通过切入点表达式,指定拦截的方法,比如指定拦截add*、search*。
引入(Introduction)
声明额外的方法或者某个类型的字段。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现IsModified接口,以便简化缓存机制。在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。
目标对象(Target Object)
被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做被通知(adviced)对象。既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxy)对象。
织入(Weaving)
指把增强应用到目标对象来创建新的代理对象的过程。Spring是在运行时完成织入。
AOP的工作流程
如下为 AOP的工作流程 + 理解的核心概念:
AOP执行流程的具体案例
补充:MVC理解点:
过程理解:
AOP切入点表达式
关键字 execution
书写规范、要求
环绕通知
——注解@Around
关于如下通知为啥要返回对原始操作的调用结果的理解:
Object:表示兼容
这里的原理就是动态代理的原理,杨超越唱完歌要说谢谢,这个谢谢代理要给他返回出去观众才能收到:
代理对象的理解:
案列——面向切面编程
切面=切点+通知
入门案例:
AOP总结
切面=切点+(绑定)通知
补充内容:基于XML schema的AOP
具体案例,代码演示:
( 不常用,培养自己的逻辑能力!)
UserDao:
package com.baowenli.demo03;
public interface UserDao {
public void insert();
public void delete();
public void update();
public void select();
}
UserDaoImpl:
package com.baowenli.demo03;
public class UserDaoImpl implements UserDao {
public void insert() {
System.out.println("添加用户信息");
}
public void delete() {
System.out.println("删除用户信息");
}
public void update() {
System.out.println("更新用户信息");
}
public void select() {
System.out.println("查询用户信息");
}
}
XmlAdvice: 通知/增强
package com.baowenli.demo03;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class XmlAdvice {
// 前置通知
public void before(JoinPoint joinPoint){
System.out.print("这是前置通知!");
System.out.print("目标类是:"+joinPoint.getTarget());
System.out.println(",被织入增强处理的目标方法为:"+
joinPoint.getSignature().getName());
}
//返回通知
public void afterReturning(JoinPoint joinPoint){
System.out.print("这是返回通知(方法不出现异常时调用)!");
System.out.println("被织入增强处理的目标方法为:"+
joinPoint.getSignature().getName());
}
/**
* 环绕通知
* ProceedingJoinPoint 是JoinPoint子接口,表示可以执行目标方法
* 1.必须是Object类型的返回值 ————表示兼容
* 2.必须接收一个参数,类型为ProceedingJoinPoint
* 3.必须throws Throwable
*/
public Object around(ProceedingJoinPoint point)throws Throwable{
System.out.println("这是环绕通知之前的部分!");
//调用目标方法
Object object=point.proceed();
System.out.println("这是环绕通知之后的部分!");
return object;
}
//异常通知
public void afterException(){
int a=1/0;
System.out.println("异常通知!");
}
//后置通知
public void after(){
System.out.println("这是后置通知!");
}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册Bean -->
<bean name="userDao" class="com.baowenli.demo03.UserDaoImpl"/>
<bean name="xmlAdvice" class="com.baowenli.demo03.XmlAdvice"/>
<!--靠逻辑:配置AOP————
1. 指定所有的切点,id不重复
2. 你要配置的是哪个切面,引用出来!
3. 前置/环绕增强,具体前置/环绕增强的方法,以及他的切入点!
-->
<!-- 配置Spring AOP-->
<aop:config>
<!-- 指定切点 -->
<aop:pointcut id="pointcut" expression="execution(*
com.baowenli.demo03.UserDaoImpl.*(..))"/>
<!--指定切面 -->
<aop:aspect ref="xmlAdvice">
<!--指定前置通知-->
<aop:before method="before" pointcut-ref="pointcut"/>
<!--指定返回通知-->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
<!--指定环绕方式-->
<aop:around method="around" pointcut-ref="pointcut"/>
<!-- 指定异常通知 -->
<aop:after-throwing method="afterException"
pointcut-ref="pointcut"/>
<!-- 指定后置通知 -->
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
applicationContext-Anno.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册Bean -->
<bean name="userDao" class="com.baowenli.demo03.UserDaoImpl"/>
<!-- <bean name="AnnoAdvice" class="com.baowenli.demo04.AnnoAdvice"/>-->
<!-- 开启@aspectj的自动代理支持 -->
<aop:aspectj-autoproxy/>
</beans>