下面是关于Spring AOP基本概念的完整攻略。
1. 什么是AOP
AOP(Aspect-Oriented Programming),即面向切面编程,是OOP(Object-Oriented Programming)的一种扩展。OOP需要在类中定义方法,在方法中编写业务逻辑代码。而AOP则通过预先定义好的切面将所有对象的横切关注点分离出来,然后统一交给切面去处理。这样既避免了大量代码的重复,又降低了业务代码和横切逻辑代码之间的耦合性。
2. Spring AOP基本概念
2.1 切面(Aspect)
切面是一种模块化的代码,通常用来处理跨越多个类(业务类)的问题。比如说,日志、事务、权限控制等。切面可以很好地模块化这些关注点并使得代码复用和维护变得更加容易。
2.2 连接点(Join point)
连接点是程序中能够使用切面的具体位置,例如方法的调用、异常的抛出、属性的读写等等。Spring AOP只支持方法级别的连接点。
2.3 通知(Advice)
通知是切面具体的业务逻辑,是实现横切逻辑的代码。通知分为前置通知(Before)、后置通知(After)、返回通知(AfterReturning)、异常通知(AfterThrowing)和环绕通知(Around)。
2.4 切入点(Pointcut)
切入点是一个表达式,指定了哪些连接点会被切面拦截。可以使用表达式语言(AspectJ expression language)指定切入点。切入点实际上就是包含了一系列连接点的集合。
2.5 引入(Introduction)
引入是一种方式,可以新增一些属性和方法到被通知的类中。引入可以让我们非常方便地向目标类中添加一些方法和属性。
2.6 目标对象(Target Object)
目标对象是我们实际编写业务逻辑的JavaBean,它是方法的执行者。
2.7 AOP代理(AOP Proxy)
AOP代理是Spring AOP框架生成的对象,它包含了目标对象和切面。在运行时,Spring AOP框架会为目标对象生成代理对象,在代理对象上应用切面。所以,我们执行的方法实际上是代理对象的方法。
3. Spring AOP示例
3.1 示例1:使用AspectJ表达式配置切入点
首先,需要添加Spring AOP和AspectJ的依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
然后,创建一个切面,并实现前置通知和后置通知。
@Aspect
@Component
public class UserServiceAspect {
@Before("execution(public * com.example.service.UserService.*(..))")
public void before(JoinPoint joinPoint) {
System.out.println("before");
}
@AfterReturning(pointcut = "execution(public * com.example.service.UserService.*(..))", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("afterReturning");
}
}
上面的代码中,使用AspectJ表达式(execution(public * com.example.service.UserService.*(..)))定义了一个切面,这个切面拦截了UserService中的所有公共方法。然后,在切面中实现了前置通知和后置通知,分别在目标方法执行前和执行后打印一段文字。
最后,在调用UserService中的方法时,Spring AOP框架会自动将切面应用到这个方法上。
3.2 示例2:使用XML配置切面和切入点
首先,需要在XML配置文件中添加如下配置:
<aop:aspectj-autoproxy />
<bean id="userServiceAspect" class="com.example.aspect.UserServiceAspect" />
<aop:config>
<aop:pointcut id="userServicePointcut" expression="execution(public * com.example.service.UserService.*(..))" />
<aop:advisor advice-ref="beforeAdvice" pointcut-ref="userServicePointcut" />
<aop:advisor advice-ref="afterAdvice" pointcut-ref="userServicePointcut" />
</aop:config>
<bean id="userService" class="com.example.service.UserService" />
其中,<aop:aspectj-autoproxy />
表示启用Spring AOP框架的自动代理功能。<bean id="userServiceAspect" class="com.example.aspect.UserServiceAspect" />
表示声明一个切面。
<aop:config>
中定义了一个切入点<aop:pointcut id="userServicePointcut" expression="execution(public * com.example.service.UserService.*(..))" />
,用来拦截UserService中的所有公共方法。
然后,通过<aop:advisor>
定义了两个通知,一个是前置通知,一个是后置通知。
最后,声明了一个UserService实例,这个实例中的所有公共方法都会被切面拦截处理。
@Service
public class UserService {
public void addUser() {
System.out.println("add user");
}
public void deleteUser() {
System.out.println("delete user");
}
}
上面的代码中,添加了一个addUser()和一个deleteUser()方法,这两个方法都是公共方法。
另外,我们需要在UserServiceAspect切面类中定义前置通知和后置通知。
@Component
public class UserServiceAspect {
public void before() {
System.out.println("before");
}
public void after() {
System.out.println("after");
}
}
最后,运行我们的程序,输出结果如下:
before
add user
after
before
delete user
after
从输出结果上可以看到,我们的切面成功拦截了UserService中的所有公共方法,并在目标方法的前面和后面执行了指定的通知。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring AOP基本概念 - Python技术站