章节目标:详细解释什么是Spring AOP思想和对于该思想实现的AspectJ框架的实现用法。
一.AOP面向切面编程
1.AOP概述
AOP(Aspect Orient Programming)面向切面编程,卖你想切面编程是从倒台角度烤炉程序运行过程。
AOP底层,采用的是动态代理模式实现的。具体实现采用了两种动态代理:JDK动态代理和CGLIB动态代理。
AOP意为面向切面编程,可以通过运行期动态代理实现程序功能的统一维护的一种思想。AOP是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度减低,提高程序的可重用性,同时提高了开发的效率。
面向切面编程,就是将交叉业务逻辑封装成切面,利用AOP容器的功能将切面织入到主业务逻辑中。所谓交叉逻辑是指,通用的和主业务逻辑没有关系的代码。如安全检查、事务、日志、缓存等。
若不使用AOP,则会出现代码纠缠,即交叉业务逻辑和主业务逻辑混合在一起,这样会使著业务逻辑混杂不清。
例如:转账业务,在实现转账业务逻辑的前后,需要权限控制,日志记录,加载事务,结束事务等交叉业务逻辑,而这些业务逻辑和主业务逻辑之间并没有直接关系。但是他们的代码量所占比重可以达到总代码量的一版甚至还多。它们的存在,不仅仅产生了大量的“冗余”代码,还大大干扰了主业务逻辑。
2.AOP思想有什么好处
3.AOP编程术语
(1)切面(Aspect)
切面泛指交叉业务逻辑,例如:事务处理、日志处理就可以理解为切面。常用的切面是通知(Advice).实际就是对业务逻辑的一种增强。
切面就是一个普通类,将用于增强目标类功能的其他功能封装到一个类中,这个类就叫切面类,切面类需要使用@Aspect注解标注,切面类中用于增强目标类功能的方法就是普通方法,通过配置文件、将切面中的功能增强到目标类的目标方法中。
二.AspectJ
1.AspectJ概述
2.AspectJ切入点表达式
3.AspectJ的通知类型
AspectJ中常用的通知类型有五种类型:
前置通知:Before()
后置通知:AfterReturning()
环绕通知:Around()
异常通知:AfterThrowing()
最终通知:After()
4.初始化Aspectj开发环境
加入Spring框架的依赖和AspectJ依赖
在使用AspectJ框架实现AOP思想的时候,要引入AOP的约束,配置文件中使用AOP约束中的标签都是AspectJ框架中的,而不是Spring框架本身的。AsprctJ对于AOP思想的实现有注解和配置文件两种方式,这里讲解的是注解方式。
5.AspectJ基于注解的方式实现AOP思想
(1)定义业务接口和实现类
(2)定义切面类
(3)在spring核心配置文件中声明 切面类和目标类对象
(4)注册AspectJ的自动代理
<?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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--把对象交给spring容器,由spring容器统一创建,管理对象-->
<!--声明目标对象-->
<bean id="someService" class="com.bjpowernode.ba01.SomeServiceImpl" />
<!--声明切面类对象-->
<bean id="myAspect" class="com.bjpowernode.ba01.MyAspect" />
<!--声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象。
创建代理对象是在内存中实现的, 修改目标对象的内存中的结构。 创建为代理对象
所以目标对象就是被修改后的代理对象.
aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象。
-->
<aop:aspectj-autoproxy />
<!--
有接口也想用cjlib实现动态代理:
如果你期望目标类有接口,使用cglib代理
proxy-target-class="true":告诉框架,要使用cglib动态代理
-->
<!-- <aop:aspectj-autoproxy proxy-target-class="true"/>-->
</beans>
6.AspectJ中实现动态代理
1.目标类有接口默认使用的是JDK动态代理;
2. 目标类没有接口默认使用的是CJLIB动态代理;
3. 目标类有接口也可以使用CJLIB动态代理,但是需要设置spring核心配置文件中的<aop:aspectj-autoproxy >标签;
修改spring的核心配置文件
<?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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--把对象交给spring容器,由spring容器统一创建,管理对象-->
<!--声明目标对象-->
<bean id="someService" class="com.bjpowernode.ba01.SomeServiceImpl" />
<!--声明切面类对象-->
<bean id="myAspect" class="com.bjpowernode.ba01.MyAspect" />
<!--声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象。
创建代理对象是在内存中实现的, 修改目标对象的内存中的结构。 创建为代理对象
所以目标对象就是被修改后的代理对象.
aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象。
-->
<aop:aspectj-autoproxy />
<!--
有接口也想用cjlib实现动态代理:
如果你期望目标类有接口,使用cglib代理
proxy-target-class="true":告诉框架,要使用cglib动态代理
-->
<!-- <aop:aspectj-autoproxy proxy-target-class="true"/>-->
</beans>
三.AspectJ的常用通知类型
1.@Before前置通知-参数JoinPoint
2.@AfterReturning后置通知-returning属性
- @Around环绕通知- ProceedingJoinPoint 参数
- @AfterThrowing异常通知-throwing属性
5.@After最终通知(相当于finally)
6.@Pointcut定义切入点