介绍
面向切面编程(AOP)作为一种补充面向对象编程(OOP)的技术,通过将通用逻辑(如事务管理、日志记录、缓存、权限控制等)封装成独立的切面,与业务代码分离,有效减少代码冗余并降低模块间的耦合度。切面指的是那些与业务逻辑无关,却会被所有业务模块调用的公共逻辑。
以一个实例来说明:如何在UserServiceImpl
类的所有方法执行前添加日志记录功能。
public class UserServiceImpl implements IUserService {
@Override
public List<User> findUserList() {
System.out.println("Executing method: findUserList");
return Collections.singletonList(new User("seven", 18));
}
@Override
public void addUser() {
System.out.println("Executing method: addUser");
// Perform some operations
}
}
通过将日志记录功能抽象为一个切面,我们实现了功能的解耦,这正是AOP的核心理念:将分散在不同业务逻辑中的重复代码通过横向切割的方式集中到一个独立的模块中!
OOP关注于业务处理过程中实体的属性和行为的抽象封装,以实现逻辑单元的清晰划分。
AOP则专注于业务处理过程中的切面提取,关注的是处理过程的特定步骤或阶段,以实现逻辑过程中各部分的低耦合隔离。这两种设计理念在目标上存在本质区别。
AOP相关术语
AOP的核心概念由AOP联盟定义,并非Spring特有。
-
切面(Aspect):切面是增强和切点的结合体,共同定义了切面的全部内容。
- 多个切面间的执行顺序可以通过@Order注解或实现Ordered接口并重写getOrder方法来控制。Ordered.getValue()返回值较低的具有更高优先级。
-
连接点(Join point):通常指方法,在Spring AOP中,连接点代表方法的执行。连接点是应用执行过程中可以插入切面的点,可以是方法调用、异常抛出、字段修改等。
-
增强(Advice):切面的工作称为增强,实际上是程序运行时通过Spring AOP框架触发的代码段。
- 前置增强(Before):在目标方法调用前执行。
- 后置增强(After):在目标方法完成后执行,不关心输出。
- 返回增强(After-returning):在目标方法成功执行后执行。
- 异常增强(After-throwing):在目标方法抛出异常后执行。
- 环绕增强(Around):增强包裹目标方法,在方法调用前后执行自定义逻辑。
-
切点(Pointcut):定义增强所要织入的一个或多个连接点。通常使用明确的类和方法名称,或利用正则表达式定义匹配的类和方法名称。
-
引入(Introduction):允许向现有类添加新方法或属性。
-
目标对象(Target Object):被一个或多个切面增强的对象,通常是一个代理对象。
-
织入(Weaving):将切面应用到目标对象并创建新的代理对象的过程。分为编译期织入、类加载期织入、运行期织入;Spring AOP在运行期织入。
execution表达式格式:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
ret-type-pattern
返回类型模式,name-pattern
名字模式和param-pattern
参数模式是必选的,其他部分可选。- 返回类型模式决定方法的返回类型必须匹配一个连接点。最常用的是
*
,代表匹配任意返回类型。 declaring-type-pattern
匹配给定类型的所有方法。name-pattern
匹配方法名,可以使用*
作为通配符。param-pattern
参数模式复杂,`()匹配不接受参数的方法,(..)匹配接受任意数量参数的方法,()匹配接受一个任意类型参数的方法,(,String)匹配接受两个参数的方法,第一个任意类型,第二个必须是String类型。
例如:
execution(* com.example.service.*.*(..))
Spring AOP和AspectJ的关系
AspectJ是一个Java实现的AOP框架,能够在编译期对Java代码进行AOP编译,使Java代码具备AspectJ的AOP功能。AspectJ是目前最成熟、功能最丰富的AOP框架,与Java程序完全兼容,易于上手。
1