一个常见的应用场景是,当我们需要在程序执行某个方法前后,进行日志记录、权限检查或者其他额外的处理操作时。这时候,我们可以使用AOP编程来实现。
一、XML配置AOP
举个例子,假设我们有一个名为`UserService`的服务类,其中包含了创建用户和更新用户信息的方法。为了在每次执行这两个方法时,都先记录一份执行日志,我们可以通过AOP来实现:
1. 创建一个切面类`LogAspect`,该类需要实现`MethodInterceptor`接口。
public class LogAspect implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 记录开始时间
long startTime = System.currentTimeMillis();
// 执行目标方法
Object result = invocation.proceed();
// 计算方法执行时间,并打印日志
long endTime = System.currentTimeMillis();
System.out.println("方法[" + invocation.getMethod().getName() + "]执行耗时" + (endTime - startTime) + "毫秒");
return result;
}
}
2. 在Spring配置文件中,将`LogAspect`类声明为一个切面,并指定要拦截的方法。
<bean id="logAspect" class="com.example.aspect.LogAspect"/>
<aop:config>
<aop:aspect ref="logAspect">
<aop:pointcut id="userServicePointCut" expression="execution(* com.example.service.UserService.*(..))" />
<aop:around pointcut-ref="userServicePointCut" method="invoke" />
</aop:aspect>
</aop:config>
【xml配置分析:这段代码是Spring AOP的配置,用于将自定义的切面类`LogAspect`应用到`UserService`服务类中的方法上。
(1)第一行定义一个ID为`logAspect`的Bean,类型为`com.example.aspect.LogAspect`,即定义了一个切面。
(2)在`aop:config`标签内声明了一个aspect(切面),引用了声明好的`logAspect`。
(3)`aop:pointcut`元素声明了一个名为`userServicePointCut`的切入点,该切入点表达式指定了要拦截的类和方法。其中`execution(* com.example.service.UserService.*(..))`表示要匹配`com.example.service.UserService`类下的任何方法。
(4)`aop:around`元素则将该切面的拦截动作设置为"环绕通知",将前置、后置通知(切面操作)和目标方法合并在一个方法体中,并控制是否执行目标方法或直接返回结果,同时在合适的时候添加新的流程处理。】
3. 重启应用程序,每次执行`UserService`中的方法时,都会在控制台上输出方法执行时间的日志记录了。
这样,我们就通过AOP编程,实现了对方法执行时间的自动记录。另外,如果要实现权限检查等其他功能,只需要添加一个类似的切面即可。
二、注解配置AOP
举个例子,假设你要在`com.example.service.UserService`类上增加日志打印的横切关注点,那么可以按以下步骤来实现:
1. 定义一个日志切面类,该类使用Aspect注解标记,并在其内部定义一个pointcut切入点(具体对应到UserService的某个方法)和一个advice增强处理逻辑,如下所示:
@Component
@Aspect
public class LogAspect {
@Pointcut("execution(* com.example.service.UserService.*(..))")
public void servicePointCut() {
}
@Around("servicePointCut()")
public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {
// 打印日志
System.out.println("Method " + joinPoint.getSignature().getName() + " is invoked.");
// 执行原有逻辑
Object result = joinPoint.proceed();
return result;
}
}
2. 在Spring配置文件中开启注解驱动的AOP自动代理机制,同时导入上述切面类,如下所示:
<context:component-scan base-package="com.example"/>
<aop:aspectj-autoproxy />
<bean id="logAspect" class="com.example.aspect.LogAspect"/>
其中第一行表示启用注解扫描,并设置扫描包路径为`com.example`,第二行则表示启用AspectJ注解的AOP自动代理机制,第三行定义的是之前实现的日志切面`LogAspect`类的Bean。
相比于XML配置方式,使用注解的方式更加简洁和灵活,能够提高开发效率,并且可以让代码更具可读性。