- 方式1:使用Spring的API接口,就是我们使用BeforeLog和AfterLog实现的那两个接口,就是Spring的API接口【通过实现spring的API】
- 方式2:自定义实现AOP【通过定义一个切面类实现】
- 方式3:使用注解实现
1.代码实现
相同的需求
- 定义一个切面类
package com.thhh.aspect; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class Annotation { @Before("execution(* com.thhh.service.UserServiceImpl.*(..))") public void before(){ System.out.println("==========执行前=========="); } @After("execution(* com.thhh.service.UserServiceImpl.*(..))") public void after(){ System.out.println("==========执行后=========="); } }
- 配置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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--注册bean--> <bean id="userServiceImpl" class="com.thhh.service.UserServiceImpl"/> <bean id="beforeLog" class="com.thhh.Log.BeforeLog"/> <bean id="afterLog" class="com.thhh.Log.AfterLog"/> <!--方式3:注解实现--> <bean id="annotationPointcut" class="com.thhh.aspect.Annotation"/><!--装配注解切面类--> <aop:aspectj-autoproxy/><!--开启aop注解支持--> </beans>
- 测试
import com.thhh.service.UserService; import com.thhh.service.UserServiceImpl; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = context.getBean("userServiceImpl", UserService.class); System.out.println(userService); userService.add(); System.out.println("==============="); userService.delete(); System.out.println("==============="); userService.update(); System.out.println("==============="); userService.query(); } }
2.环绕通知
使用注解 @Around(“execution(表达式)”)修饰方法即可
- 环绕通知和其他的通知增强不同,我们需要设置一个参数来获取切入点,即要执行的核心方法,这个参数类型为ProceedingJoinPoint(连接点),这个参数会自动传入,我们直接使用即可
- 在环绕通知的内部,我们需要显式的执行pj.proceed(),否则我们的核心方法将不会执行,而只会执行我们的环绕通知
package com.thhh.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class Annotation {
@Before("execution(* com.thhh.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("==========执行前==========");
}
@After("execution(* com.thhh.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("==========执行后==========");
}
//环绕通知和其他的通知增强不同,我们需要设置一个参数来获取切入点,即要执行的核心方法,这个参数类型为ProceedingJoinPoint(连接点)
//在环绕通知的内部,我们需要显式的执行pj.proceed(),否则我们的核心方法将不会执行,而只会执行我们的环绕通知
@Around("execution(* com.thhh.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint pj) throws Throwable {
System.out.println("==========环绕前==========");
//Object proceed = pj.proceed();//不调用proceed()方法
System.out.println("==========环绕后==========");
}
}
@Around("execution(* com.thhh.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint pj) throws Throwable {
System.out.println("==========环绕前==========");
Object proceed = pj.proceed();//执行核心方法
System.out.println("==========环绕后==========");
}
@Around("execution(* com.thhh.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint pj) throws Throwable {
System.out.println("==========环绕前==========");
Object proceed = pj.proceed();//执行核心方法
System.out.println("==========环绕后==========");
Signature signature = pj.getSignature();//获取类的签名,就是获取这个类的全名
System.out.println(signature);
}
3.Spring实现代理模式的方式
前面我们讲代理模式的时候就讲过了,代理模式一共有3种实现方式
- JDK实现
- cglib实现
- javassist实现
在spring中,支持了前两种的代理模式实现,在默认情况下,spring使用JDK实现,就是我们讲动态代理的时候那样,手动的写了一个动态代理类;我们可以在spring的配置文件中手动的切换,使得spring使用cglib实现代理模式
切换方法
二者在执行的效果上没有什么区别
4.小结
在使用了3种实现spring中的AOP方法之后,我们可以明显察觉到,Spring中的AOP就是我们学习的动态代理模式,只是通过spring来实现了,改名为AOP
相比较于上面3种方式,推荐使用方法2,即自定义切面实现AOP,方法3虽然简单,但是不能复用execution表达式,显得很冗余
AOP就是一种思想,是一种横向编程的思想;在不影响原来业务类的情况下,实现业务动态的增强