AOP(Aspect Oriented Programming)被称为“面向切面儿编程”。
“通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。”
与AspectJ的静态代理不同,Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler
接口和Proxy
类。
如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final
,那么它是无法使用CGLIB做动态代理的。
step 1 导包:
step 2 配置文件:
<context:component-scan base-package="spring"/>
<aop:aspectj-autoproxy/>
<aop:aspectj-autoproxy/>与@Aspect配合使用
step 3 编写AOP组件:
@Component
@Aspect
public class DemoAspect {
@Before("bean(hello)")
public void demo() {
System.out.println("this is aop!");
}
}
通知:用于声明 切面方法 的执行位置
- @Before 在目标方法之前执行切面方法
- @After 在目标方法之后执行切面方法, 无论是否有异常,都执行
- @AfterReturning 在方法正常结束以后
- @AfterThrowing 在方法出现异常以后
- @Around 环绕通知
//环绕通知:
//1. 方法必须有返回值
//2. 方法必须有参数ProceedingJoinPoint
// 称为处理连接点
//3. 在方法中调用 jp.proceed() 就在执行目标的
// 业务方法, 返回值就是目标方法的执行结果
//4. jp.proceed() 方法执行出现异常, 就是
// 目标业务方法执行期间出现异常
@Around("bean(userService)")
public Object test4(
ProceedingJoinPoint jp)
throws Throwable{
System.out.println("开始");
Object val = jp.proceed();
System.out.println("结束:"+val);
return val;
}
切入点表达式:指定 AOP 的切入(织入)范围
Bean组件切入点
- "bean(userService)" 切入到 userService 的全部方法
- "bean(userService)||bean(cartService)"
- "bean(*Service)" 切入到系列Service的全部方法
类切入点
- "within(cn.tedu.store.service.UserServiceImpl)"
- 切入到UserServiceImpl中的全部方法
- "within(cn.tedu.store.service.*ServiceImpl)"
- 切入到 *ServiceImpl 系列实现类的全部方法
- "within(cn.tedu.store..*Impl)"
- 切入到 cn.tedu.store 下的某个包, 其中*Impl系列类的全部方法
方法切入点
- 语法"execution(返回值 类全名.方法名(参数类型))"
- "executuion(* cn.tedu.store.service.IUserService.login(..))"
- 切入到 login 方法上
- "executuion(* cn.tedu.store.service.IUserService.get*(..))"
- 切入到 login 方法上
- "executuion(* cn.tedu.store.service.Service.get(..))"
- "executuion(* cn.tedu.store..Service.get(..))"
参考文章: