Spring 面向切面编程AOP实现详解
什么是AOP
AOP(Aspect Oriented Programming)即面向切面编程,是一种编程思想,它把程序的业务逻辑和系统内部的非业务逻辑分离开来,以便更好地重用两部分逻辑,提高代码的灵活性和可维护性。
AOP的实现方式
AOP有多种实现方式,包括基于继承的方式、基于代理的方式等,但Spring框架采用的是基于代理的方式。
基于代理的方式需要对目标对象进行代理,将非业务逻辑和业务逻辑进行分离,并使用代理对象完成具体的业务逻辑。
Spring AOP的实现
Spring框架的AOP实现主要依赖于以下三个概念:
-
切面(Aspect):由切点和通知组成的一个横纵交叉的区域,用于定义切入点和切入点之前/之后执行的逻辑。
-
切点(Pointcut):用于指定切入哪些类的哪些方法,并定义了切入点的位置。
-
通知(Advice):定义了具体要执行的逻辑,包括before、after、afterReturning、afterThrowing、around等类型的通知。
在Spring AOP中,我们需要自定义切面来实现AOP的横向切入,步骤如下:
- 定义切入点
在Spring AOP中,可以使用注解和XML配置2种方式定义切入点。
- 使用注解方式:在目标类或者切面类的方法上添加@Pointcut注解来表示切入点。例如:
java
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethod() {}
- 使用XML配置方式:通过配置
<aop:config>
和<aop:pointcut>
元素来定义切入点。例如:
xml
<aop:config>
<aop:pointcut id="serviceMethod" expression="execution(* com.example.service.*.*(..))"/>
</aop:config>
- 定义通知
在Spring AOP中,可以使用注解和XML配置2种方式来定义通知:
- 使用注解方式:在切面类的方法上添加@Around、@Before、@After、@AfterReturning、@AfterThrowing注解来定义具体的通知类型和具体的代码逻辑。例如:
java
@Around("serviceMethod()")
public Object aroundService(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = null;
// 面向切面的代码逻辑
return result;
}
- 使用XML配置方式:通过配置
<aop:aspect>
和<aop:before>
、<aop:after>
、<aop:after-returning>
、<aop:after-throwing>
等元素来定义通知类型和具体的代码逻辑。例如:
xml
<aop:aspect ref="serviceAspect">
<aop:around pointcut-ref="serviceMethod" method="aroundService"/>
</aop:aspect>
Spring AOP示例
下面,我们以一个用户服务类为例,来演示如何使用Spring AOP实现日志信息的拦截打印。
示例1:注解方式
UserServiceImpl.java 文件:
@Service
public class UserServiceImpl implements UserService {
@Override
public User getUserById(Integer id) {
return new User(id, "张三");
}
@Override
@LogAnnotation(name = "用户服务类测试方法")
public void test() {
System.out.println("测试完成");
}
}
LogAspect.java 文件:
@Aspect
@Component
public class LogAspect {
@Pointcut("@annotation(com.example.demo.annotation.LogAnnotation)")
private void logPointCut() {}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
String name = annotation.name();
System.out.println("打印日志信息:【" + name + "】开始执行");
Object result = point.proceed();
System.out.println("打印日志信息:【" + name + "】执行结束");
return result;
}
}
在上面的示例中,我们在UserServiceImpl
类的test()
方法上添加了一个自定义注解@LogAnnotation
,表示这是一种需要进行日志拦截打印的方法,然后在LogAspect
类中定义了一个logPointCut()
切入点和一个around()
通知,用来实现日志拦截打印的功能。
示例2:XML配置方式
UserServiceImpl.java 文件同上。
LogAspect.java 文件:
public class LogAspect {
public void beforeAdvice(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println("打印日志信息:【" + method.getName() + "】开始执行");
}
public void afterAdvice(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println("打印日志信息:【" + method.getName() + "】执行结束");
}
}
spring-config.xml 文件:
<aop:config>
<aop:advisor advice-ref="logAdvice" pointcut="execution(* com.example.demo.service.*.*(..))"/>
</aop:config>
<bean id="logAdvice" class="com.example.demo.aop.LogAspect">
<aop:before method="beforeAdvice" pointcut="execution(* com.example.demo.service.*.*(..))"/>
<aop:after method="afterAdvice" pointcut="execution(* com.example.demo.service.*.*(..))"/>
</bean>
在上面的示例中,我们使用XML配置方式来定义了切入点和通知,并将它们添加到了aop:config
元素中,以便将所有的切入点和通知与目标对象相关联。同时,我们还在spring-config.xml
配置文件中定义了logAdvice
bean,指定了beforeAdvice()
和afterAdvice()
等具体的拦截打印逻辑。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring 面向切面编程AOP实现详解 - Python技术站