AOP 的概述
什么是 AOP
在软件业,AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。==AOP 是 OOP 的延续==,是软件开发中的一个热点,也是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。——————百度百科
Spring 底层的 AOP 实现原理
动态代理
- JDK 动态代理:只能对实现了接口的类产生代理
- Cglib 动态代理:对没有实现接口的类产生代理。生产子类对象
++ 动态代理相关详细请看《java 代理模式的那些事》++
Spring 的 AOP 的开发
Spring 的 AOP 的简介
AOP 思想最早由 AOP 联盟组织提出的,Spring 是使用这种思想最好的框架。前期,Spring 的 AOP 也有自己的实现方式,但是非常繁琐。不过当时有一款非常好的 AOP 框架-AspectJ,Spring 便引入 AspectJ 作为自身的 AOP。so,Spring 有两套 AOP 开发方式:Spring 传统方式、Spring 基于 AspectJ 的方式。
AOP 开发中的术语
- Joinpoint:连接点,可以被拦截到的点(方法、类)。
- Pointcut:切入点,真正被拦截到的点(方法、类)。
- Advice:通知(或者叫增强),对切入点进行权限校验等动作的方法称为通知(方法层面的增强)。
- Introduction:引介,类层面的增强
- Target:被增强的对象
- Weaving:织入,将通知(Advice)应用到目标(Target)过程。
- proxy:代理对象
- Aspect:切面,多个通知和多个切入点组合
Class UserDao{
public void save();
public void find();
public void update();
public void delete();
}
/**
* save、find、update、delete方法都可以被称为连接点
* 如果在实际开发中,只对save方法进行增强,则save被称为切入点
* 如果现在要对save方法进行权限校验(checkPri();),则权限校验(checkPri();)的方法则称为通知
* Target是指被增强的对象,也就是UserDao
*/
进入 AspectJ 的 XML 方式开发
创建 web 项目,引入 jar 包
- 引入 Spring 的 6 个基本 jar 包(commons-logging、log4j、beans、context、core、expression)
- 引入 AOP 开发的相关 jar 包(aop、aspects)
- 引入 aop 的 XML 约束
<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">
</beans>
编写目标类并完成配置
public class ProductDaoImpl implements ProductDao{
public void save(){
//TODO
}
public void update(){
//TODO
}
public void find(){
//TODO
}
public void delete(){
//TODO
}
}
<!-- 配置目标对象:被增强的对象 -->
<bean id="productDao" class="com.spring.demo.ProductDaoImpl" />
编写测试类
@RunWith(SpringJunit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo{
@Resource(name="productDao")
private ProductDao productDao;
@Test
public void demo1(){
productDao.save();
productDao.update();
productDao.find();
productDao.delete();
}
}
编写切面类
//切面类
public class MyAspectXML{
public void checkPri(){
System.out.println("权限校验。。。。。。。。");
}
}
<!-- 将切面类交给Spring管理 -->
<bean id="myAspect" class="com.spring.demo.MyAspectXML" />
通过 AOP 的配置来实现目标代理
<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 id="productDao" class="com.spring.demo.ProductDaoImpl" />
<!-- 将切面类交给Spring管理 -->
<bean id="myAspect" class="com.spring.demo.MyAspectXML" />
<!-- 通过AOP的配置完成对目标类产生代理 -->
<aop:config>
<!-- experssion:通过表达式配置哪些类的哪些方法需要进行增强 -->
<aop:pointcut experssion="execution(* com.spring.demo.ProductDaoImpl.save(..))" id="pointcut1"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspect">
<aop:before method="checkPri" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
</beans>
Spring 中的通知类型
前置通知:在目标方法执行之前进行操作
获得切入点信息
<aop:aspect ref="myAspect">
<aop:before method="checkPri" pointcut-ref="pointcut1"/>
</aop:aspect>
后置通知:在目标方法执行之后进行操作
获得方法的返回值
<aop:aspect ref="myAspect">
<aop:after-returning method="checkPri" pointcut-ref="pointcut1" returning="result"/>
</aop:aspect>
环绕通知:在目标方法执行前后进行操作
环绕通知可以阻止目标方法的执行(ProceedingJoinPoint.proceed() 执行切入点)
<aop:aspect ref="myAspect">
<aop:around method="checkPri" pointcut-ref="pointcut1"/>
</aop:aspect>
异常抛出通知:在程序出现异常的时候,进行的操作
<aop:aspect ref="myAspect">
<aop:after-throwing method="checkPri" pointcut-ref="pointcut1" throwing="ex"/>
最终通知:无论代码时候有异常,总是会执行。(相当于 try catch 中的 finally)
<aop:aspect ref="myAspect">
<aop:after method="checkPri" pointcut-ref="pointcut1"/>
Spring 的切入点表达式的写法
==基于 execution 的函数完成的==
基本语法:
- [访问修饰符] 方法返回值 包名.类名.方法名(参数)
- public void com.spring.demo.UserDao.save(..)
- public 可省略。返回值可以是具体的 String void,也可以是
*
表示任意返回值。..
表示任意参数
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于