一、什么是AOP?
这是一种编程思想,而不是某种特定的技术。它的作用主要是将重复的代码抽取出来,然后再织入到程序中。最好理解的例子就是Javaweb中的过滤器filter,就是有这种面向切面编程的思想。
二、AOP是基于什么实现的呢?
aop基于动态代理(spring优先选择JDK的Proxy代理,但是spring不要我们去实现动态代理,我们只需要进行一定的配置即可)
Proxy: 被代理的对象必须实现接口
Cglib: 被代理的对象不能被final修饰,基于继承
三、AOP的专用的术语
切入点:最终增强的方法
通知/增强:代理中增强的代码
切面:通知+切入点,通知应用到哪个切入点
目标:被代理对象
织入:将切面的代码应用到目标对象的过程
代理:增强被代理对象生成一个增强的代理对象
四、AOP有五种通知类型:
前置通知before,在方法前执行通知
最终通知after,无论方法是否执行成功,该通知都会执行,有点finally的感觉
成功通知afterReturning ,方法执行成功才执行
异常通知afterThrowing,方法执行出现异常执行
环绕通知around,可以自定义通知执行位置
五、举个例子理解上面的名词:
1.先导包:
<!-- spring的aop支持 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.10</version>
</dependency>
<!-- spring上下文支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- spring整合junit测试 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.8.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- junit测试支持 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
2.创建通知对象的目标对象
AccountService接口
public interface AccountService {
public void save()
}
AccountServiceImpl 实现AccountService接口
public class AccountServiceImpl implements AccountService {
@Override
public void save() {
System.out.println("save操作");
//int a = 1/0;
}
3.创建通知对象
public class MyAdvice {
//前置通知,在目标方法执行前先执行
public void before() {
System.out.println("前置通知");
}
//最终通知,无论目标方法是否成功执行,最终都会执行该通知
public void after() {
System.out.println("后置通知");
}
//成功通知,目标方法成功执行后才执行该通知
public void afterReturning() {
System.out.println("成功通知");
}
//异常通知,目标方法执行出现异常才执行该通知
public void afterThrowing() {
System.out.println("异常通知");
}
//环绕通知,手动调用目标方法,可以设置通知的位置
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知前");
pjp.proceed();//调用目标方法
System.out.println("环绕通知后");
}
}
注意,环绕通知红框中是固定用法

4.aop配置文件
<?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:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置通知的目标对象 -->
<bean name="accountService" class="com.spring_demo.ioc.service.AccountServiceImpl"></bean>
<!-- 配置通知对象 -->
<bean name="advice" class="com.spring_demo.aop.MyAdvice"></bean>
<!-- 配置aop -->
<aop:config>
<!-- 配置切点 -->
<aop:pointcut expression="execution (public * com.spring_demo.ioc.service.*ServiceImpl.*(..))" id="pc"/>
<!--配置切面 -->
<aop:aspect ref="advice">
<aop:before method="before" pointcut-ref="pc"/>
<aop:after method="after" pointcut-ref="pc"/>
<aop:after-returning method="afterReturning" pointcut-ref="pc"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pc"/>
<aop:around method="around" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
<!-- 开启注解 -->
<context:annotation-config></context:annotation-config>
</beans>
*通配符,该通配符主要用于匹配单个单词,或者是以某个词为前缀或后缀的单词
…通配符,该通配符表示0个或多个项
切点表达式:public * com.spring_demo.ioc.service.*ServiceImpl.*(..)
表达式表示在包com.spring_demo.ioc.service下以ServiceImpl结尾的类的所有公共方法,无论返回值是什么?方法名是什么?方法参数是什么?都是切点
第一个"*“表示无论方法是什么返回值类型都是切点,你可以自定义未void/int等等(则表示只有返回值类型跟你配置一样时才是切点)
第二个”*“表示以ServiceImpl结尾的类
第三个”*"表示无论方法名是什么
最后(..)表示无法方法参数是什么

5.进行测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-aop.xml")
public class TestAOP {
@Resource(name="accountService")
AccountService accountService;
@Test
public void test1() {
accountService.save();
}
}
下面是加载class中的配置文件applicationContext-aop.xml

测试结果:

修改AccountServiceImpl的代码,增加异常代码int a=1/0;:
public class AccountServiceImpl implements AccountService {
@Override
public void save() {
System.out.println("save操作");
int a = 1/0;
}
再次测试,发现异常通知执行,成功通知没有执行:

本文深入解析了面向切面编程(AOP)的概念,包括其基于动态代理的实现方式,以及在Spring框架中的具体应用。通过实例详细介绍了AOP的术语如切入点、通知、切面等,并演示了五种通知类型的使用方法。

920

被折叠的 条评论
为什么被折叠?



