Spring AOP编程

AOP

概念

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

作用

实际开发过程中,利用AOP编程技术可以实现如:日志记录、性能统计、安全控制、事务处理、异常处理等操作。

相关术语:
  • Joinpoint(连接点):指可以被拦截到的点,Spring中指拦截的方法,因为Spring只支持方法类型的连接点。
  • Pointcut(切入点):指我们要对哪些Joinpoint进行拦截的定义。
  • Advice(通知/增强):指拦截到Joinpoint之后要做的事(增强的代码)。通知分为:前置通知、后置通知、环绕通知、异常通知、最终通知
  • Introduction(引介):引介是一种特殊的通知,在不修改类代码的前提下,Introduction可以在运行期为类动态添加一些方法或Field。
  • Target(目标对象):代理的目标对象。
  • Weaving(织入):指把增强应用到目标对象来创建新的代理对象的过程。(Spring使用动态代理织入,而AspectJ采用编译期织入和类装载期织入)
  • Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类。
  • Aspect(切面):切入点和通知(引介)的结合。
实现方式
  • JDK动态代理
  • CGLIB
  • AspectJ
思想

底层思想:代理机制。

AOP并非代替OOP,而是用来解决OOP中的一些问题。


Spring AOP

  • 概念:

    Spring AOP是使用Java实现,不需要专门的编译过程和编译器,在类运行期通过代理方式向目标类植入增强代码。

    AOP思想是由AOP联盟组织提出,且为通知Advice定义了org.aopalliance.aop.interface.Advice

  • Spring提供的通知类型:

    1. 前置通知(前置增强):org.springframework.aop.MethodBeforeAdvice
    2. 后置通知(后置增强):org.springframework.aop.AfterReturningAdvice
    3. 环绕通知(环绕增强):org.aopalliance.intercept.MethodInterceptor
    4. 异常抛出通知(异常抛出增强):org.springframework.aop.ThrowsAdvice
    5. 引介通知(引介增强):org.springframework.aop.IntroductionInterceptor
  • Spring提供的切面类型:

    1. Advisor:代表一般切面,Advice本身就是一个切面,对目标类所有方法进行拦截(不带切点的切面)。
    2. PointcutAdvisor:代表具有切点的切面,可以指定拦截目标类哪些方法。
    3. IntroductionAdvisor:代表引介切面,针对引介通知而使用切面。

如果类实现接口,Spring自动采用JDK动态代理,产生代理对象。

如果类没有实现接口,那么自动采用CGLIB动态代理,产生代理对象

不要将类设置为final,无法被继承,不能产生代理对象。

JDK动态代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.danyuantech.aop;
import com.danyuantech.aop.dao.UserDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MJDKProxy implements InvocationHandler {
//注入被代理对象
private UserDao userDao;
public MJDKProxy(UserDao userDao) {
this.userDao = userDao;
}
/**
* 生成代理对象
*
* @return
*/
public UserDao createProxy() {
UserDao proxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), this);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("save".equals(method.getName())) {
// 执行的是save()方法
System.out.println("=====>记录日志<=====");
}
return method.invoke(userDao, args);
}
}
CGLIB

CGLIB(Code Generation Library)是一个开源项目!
是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate支持它来实现PO(Persistent Object 持久化对象)字节码的动态生成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.danyuantech.aop;
import com.danyuantech.aop.dao.OrderDao;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* CGLIB代理
*/
public class MCGLIBProxy implements MethodInterceptor {
//注入被代理对象
private OrderDao orderDao;
public MCGLIBProxy(OrderDao orderDao) {
this.orderDao = orderDao;
}
/**
* 生成代理对象
*
* @return
*/
public OrderDao createProxy() {
// 创建CGLIB的核心类
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(orderDao.getClass());
// 设置回调
enhancer.setCallback(this);
// 生成代理对象
OrderDao proxy = (OrderDao) enhancer.create();
return proxy;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if ("save".equals(method.getName())){
Object object = methodProxy.invokeSuper(proxy, args);
System.out.println("=====>记录日志...<=====");
return object;
}else {
return methodProxy.invokeSuper(proxy, args);
}
}
}
Spring传统AOP开发:不带切点切面(增强类中所有方法)

自定义通知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.danyuantech.aop.advice;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/**
* 前置增强
*/
public class MBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("=======>前置增强<=======");
}
}

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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">
<!-- AspectJ开发 注解开发配置这一项即可 底层使用AnnotationAwareAspectJAutoProxy-->
<aop:aspectj-autoproxy/>
<!-- 目标对象 -->
<bean id="userDao" class="com.danyuantech.aop.dao.impl.UserDaoImpl"/>
<!-- 配置增强 -->
<bean id="beforeAdvice" class="com.danyuantech.aop.advice.MBeforeAdvice"/>
<!-- 生成代理 -->
<bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 注入属性 -->
<property name="target" ref="userDao"/>
<!-- 配置代理实现接口 -->
<property name="proxyInterfaces" value="com.danyuantech.aop.dao.UserDao"/>
<!-- 配置增强 使用value -->
<property name="interceptorNames" value="beforeAdvice"/>
<!-- 是否强制使用CGLIB -->
<!--<property name="optimize" value="false"/>-->
</bean>
</beans>

AOPTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.danyuantech.aop;
import com.danyuantech.aop.dao.UserDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AOPTest {
@Resource(name = "userDaoProxy")
private UserDao userDao;
@Test
public void aopTest() {
userDao.save();
userDao.delete();
userDao.update();
userDao.find();
}
}
Spring传统AOP开发:带有切点切面(增强类中某些方法)

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?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">
<!-- AspectJ开发 注解开发配置这一项即可 底层使用AnnotationAwareAspectJAutoProxy-->
<aop:aspectj-autoproxy/>
<!-- 目标对象 -->
<bean id="userDao" class="com.danyuantech.aop.dao.impl.UserDaoImpl"/>
<!-- 配置增强 -->
<bean id="aroundAdvice" class="com.danyuantech.aop.advice.MAroundAdvice"/>
<!-- 配置切面 -->
<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!-- <property name="pattern" value=".*"/> value使用正则表达式表示-->
<property name="pattern" value="com.danyuantech.aop.dao.UserDao.save"/>
<property name="advice" ref="aroundAdvice"/>
</bean>
<!-- 生成代理 -->
<bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 注入属性 -->
<property name="target" value="userDao"/>
<!-- 配置代理对象类 -->
<property name="proxyTargetClass" value="true"/>
<!-- 配置增强 使用value -->
<property name="interceptorNames" value="aroundAdvice"/>
</bean>
</beans>

AOPTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.danyuantech.aop;
import com.danyuantech.aop.dao.UserDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AOPTest {
@Resource(name = "userDaoProxy")
private UserDao userDao;
@Test
public void aopTest() {
userDao.save();
userDao.delete();
userDao.update();
userDao.find();
}
}
Spring传统AOP开发:自动代理

在使用ProxyFactoryBean进行代理时会发现,如果有多个类需要生成代理,它就需要多个配置,相当繁琐,且代码量大。

于是Spring AOP还提供了自动代理的方式,自动代理有三种方式:

自动代理的原理:

BeanNameAutoProxyCreator和DefaultAdvisorAutoProxyCreator是基于BeanPostProcessor完成代理。(看源码)

自动代理和ProxyFactoryBean方法区别:

自动代理基于BeanPostProcessor代理方式,生成这个Bean的时候要执行后处理Bean,返回Bean本身就是代理对象。

ProxyFactoryBean生成代理,需要先有目标对象,将目标对象传入到代理对象中,生成代理对象。

Spring传统AOP开发:基于Bean名称的自动代理

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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">
<!-- AspectJ开发 注解开发配置这一项即可 底层使用AnnotationAwareAspectJAutoProxy-->
<aop:aspectj-autoproxy/>
<!-- 目标对象 -->
<bean id="userDao" class="com.danyuantech.aop.dao.impl.UserDaoImpl"/>
<!-- 配置增强 -->
<bean id="beforeAdvice" class="com.danyuantech.aop.advice.MBeforeAdvice"/>
<!-- 自动生成代理:根据Bean名称生成 -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="*.Dao"/>
<property name="interceptorNames">
<list>
<value> beforeAdvice </value>
</list>
</property>
</bean>
</beans>

AOPTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.danyuantech.aop;
import com.danyuantech.aop.dao.UserDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext5.xml")
public class AOPTest5 {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void aopTest5() {
userDao.save();
userDao.delete();
userDao.update();
userDao.find();
}
}
Spring传统AOP开发:根据切面信息自动代理

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?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">
<!-- AspectJ开发 注解开发配置这一项即可 底层使用AnnotationAwareAspectJAutoProxy-->
<aop:aspectj-autoproxy/>
<!-- 目标对象 -->
<bean id="userDao" class="com.danyuantech.aop.dao.impl.UserDaoImpl"/>
<!-- 配置增强 -->
<bean id="beforeAdvice" class="com.danyuantech.aop.advice.MBeforeAdvice"/>
<!-- 配置增强 -->
<bean id="aroundAdvice" class="com.danyuantech.aop.advice.MAroundAdvice"/>
<!-- 配置切面 -->
<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="pattern" value="com.danyuantech.aop.dao.UserDao.save"/>
<property name="advice" ref="aroundAdvice"/>
</bean>
<!-- 根据切面信息生成代理对象 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
</bean>
</beans>

AOPTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.danyuantech.aop;
import com.danyuantech.aop.dao.UserDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext6.xml")
public class AOPTest6 {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void aopTest6() {
userDao.save();
userDao.delete();
userDao.update();
userDao.find();
}
}

AspectJ

AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持。AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的植入。

快速入门

切面:切入点(Pointcut)和通知(Advice)的组合

定义切面:@Aspect 定义在类上的注解,类是一个切面

定义通知:

  • @Before:前置通知,相当于BeforeAdvice
  • @AfterReturning:后置通知,相当于AfterReturningAdvice
  • @Around:环绕通知,相当于MethodInterceptor
  • @AfterThrowing:抛出通知,相当于ThrowAdvice
  • @After:最终通知,不管是否异常,该通知都会执行
  • @DeclareParents:引介通知,相当于IntroductionInterceptor 切点表达式语言:

定义通知时,注解中value的格式:【execution(<访问修饰符> ? <方法返回值类型> <方法名称> <(..)参数>)】

举个栗子:

  • 匹配所有类public方法 execution(public * *(..))
  • 匹配指定包下所有类方法(不包含子包) execution(* com.danyuantech.dao.*(..))
  • 匹配指定包下所有类方法(包含子包)execution(* com.danyuantech.dao..*(..))
  • 匹配指定类所有方法 execution(* com.danyuantech.serviceUserService.*(..))
  • 匹配实现特定接口所有类方法 execution(* com.danyuantech.dao.GenericDAO+.*(..))
  • 匹配所有save开头的方法 execution(* save*(..))

MAspect.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package com.danyuantech.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
/**
* 定义切面
*/
@Aspect
public class MAspect {
/**
* 前置通知
*
* @param joinPoint 连接点(可选)
*/
@Before("execution(* com.danyuantech.aop.dao.UserDao.save(..))")
public void before(JoinPoint joinPoint) {
System.out.println(">>>>>>前置通知" + joinPoint + "<<<<<<");
}
/**
* 后置通知 可以获取方法的返回值
*/
@AfterReturning(value = "execution(* com.danyuantech.aop.dao.UserDao.delete(..))", returning = "result")
public void afterReturning(Object result) {
System.out.println(">>>>>>后置通知" + result + "<<<<<<");
}
/**
* 环绕通知
*
* @param joinPoint 可执行连接点
*/
@Around("execution(* com.danyuantech.aop.dao.UserDao.update(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(">>>>>>环绕前通知<<<<<<");
//执行目标方法,如果不调用则目标方法不执行...
Object proceed = joinPoint.proceed();
System.out.println(">>>>>>环绕后通知<<<<<<");
return proceed;
}
/**
* 异常通知(可以获得异常信息)
*
* @param e 异常信息
*/
@AfterThrowing(value = "MAspect.customPointcut()", throwing = "e")
public void afterThrowing(Throwable e) {
System.out.println(">>>>>>异常抛出通知:" + e + "<<<<<<");
}
/**
* 最终通知
*/
@After("MAspect.customPointcut()")
public void after() {
System.out.println(">>>>>>最终通知<<<<<<");
}
/**
* 自定义切入点(方法名随意)
*/
@Pointcut("execution(* com.danyuantech.aop.dao.UserDao.find(..))")
private void customPointcut(){}
}

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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">
<!-- AspectJ开发 注解开发配置这一项即可 底层使用AnnotationAwareAspectJAutoProxy自动生成代理-->
<aop:aspectj-autoproxy/>
<!-- 目标对象 -->
<bean id="userDao" class="com.danyuantech.aop.dao.impl.UserDaoImpl"/>
<!-- 配置切面类 -->
<bean id="mAspect" class="com.danyuantech.aop.MAspect"/>
</beans>

AspectTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.danyuantech.aop;
import com.danyuantech.aop.dao.UserDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AspectTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void aspectTest(){
userDao.save();
userDao.delete();
userDao.update();
userDao.find();
}
}

Advisor和Aspect的区别:

Advisor:是传统AOP开发中的切面。传统切面:一般由一个切入点和一个通知组合。

Aspect:真正意义上的切面,可以由多个切入点和多个通知组合。

AspectJ的XML定义

编写切面类MAspectXML.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.danyuantech.aop;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* 使用XML配置Aspect
*/
public class MAspectXML {
/**
* 前置通知
*/
public void before() {
System.out.println(">>>>>>前置通知<<<<<<");
}
/**
* 后置通知 可以获取方法的返回值
*/
public void afterReturning(Object result) {
System.out.println(">>>>>>后置通知" + result + "<<<<<<");
}
/**
* 环绕通知
*
* @param joinPoint
*/
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(">>>>>>环绕前通知<<<<<<");
//执行目标方法,如果不调用则目标方法不执行...
joinPoint.proceed();
System.out.println(">>>>>>环绕后通知<<<<<<");
}
/**
* 异常通知(可以获得异常信息)
*
* @param e 异常信息
*/
public void afterThrowing(Throwable e) {
System.out.println(">>>>>>异常抛出通知:" + e + "<<<<<<");
}
/**
* 最终通知
*/
public void after() {
System.out.println(">>>>>>最终通知<<<<<<");
}
}

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?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 id="orderDao" class="com.danyuantech.aop.dao.impl.OrderDaoImpl"/>
<!-- 配置切面类 -->
<bean id="mAspectXML" class="com.danyuantech.aop.MAspectXML"/>
<!-- AOP配置 -->
<aop:config>
<!-- 定义切点 id即为我们使用注解定义切点的名称(无意义可随意起名)-->
<aop:pointcut id="pointcut1" expression="execution(* com.danyuantech.aop.dao.OrderDao.save(..))"/>
<aop:pointcut id="pointcut2" expression="execution(* com.danyuantech.aop.dao.OrderDao.delete(..))"/>
<aop:pointcut id="pointcut3" expression="execution(* com.danyuantech.aop.dao.OrderDao.update(..))"/>
<aop:pointcut id="pointcut4" expression="execution(* com.danyuantech.aop.dao.OrderDao.find(..))"/>
<!-- 配置切面 -->
<aop:aspect ref="mAspectXML">
<!-- 运用前置增强 -->
<aop:before method="before" pointcut-ref="pointcut1"/>
<!-- 运用后置增强 -->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut2" returning="result"/>
<!-- 运用环绕增强 -->
<aop:around method="around" pointcut-ref="pointcut3"/>
<!-- 运用异常抛出增强 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="e"/>
<!-- 运用最终增强 -->
<aop:after method="after" pointcut-ref="pointcut4"/>
</aop:aspect>
</aop:config>
</beans>
如果帮到了你,想打赏支持,喏~