Spring AOP

本文详细解释了面向切面编程(AOP)的概念及其优势,包括切面、连接点、通知、切入点等术语,并通过实例展示了如何实现AOP以优化代码结构,提升效率。此外,文章还阐述了AOP的实现原理,从组件注解到代理创建过程,提供了一个全面的AOP学习指南。

AOP
什么是AOP?
AOP是指面向切面编程,是通过动态代理的方式为程序添加统一功能,解决一些公共问题,如:日志、鉴权和异常处理等。
好处:降低代码耦合度,使开发人员聚焦业务,公共统一处理,修改方便。

AOP的术语
1、切面Aspect:多个类都关注的方法
2、连接点Join point:代表一个方法的调用
3、Advice通知:我们要在切面上做什么事情(动作-action)
4、Pointcut切入点:用来描述我们要在哪些地方执行
5、Target object目标对象:被一个或多个切面通知的对象

AOP有哪些常用的注解?
@Aspect:在类上使用@Aspect可使之成为切面类
@Before(“execution(* com.qcc.beans.aop..(…))”):前置通知
@After(“execution(* com.qcc.beans.aop..(…))”):后置通知
@Around(“execution(* aop.service.impl.BusinessServiceImpl.(…))"):环绕通知,可以在方法的调用前后完成自定义行为,甚至可以选择不调用方法和修改返回对象,这是和前置后置通知的区别。
@AfterThrowing(value="execution(
com.qcc.beans.aop..(…))”,throwing=“e”):异常通知
@AfterReturning(value=“execution(* com.qcc.beans.aop..(…))”,returning=“result”):返回通知

如何实现AOP?
举例:设计性能拦截器,用于打印服务层所有方法的执行时间。
1、业务服务接口

public interface IBusinessService {
    //业务执行方法A
    void executeBusinessA();
    //业务执行方法B
    void executeBusinessB();
}

2、业务实现类

@Service("businessService")
public class BusinessServiceImpl implements IBusinessService {
public void executeBusinessA() {
        logger.info("executing business in methodA");
    }
    public void executeBusinessB() {
    	logger.info("executing business in methodB");
    }
}

3、性能分析器

@Component // 放入IOC容器
@Aspect // 切面类
public class PerformanceAnalysisInterceptor {
// 切入点是所有方法
public static final String POINTCUT = 
"execution (* aop.service.impl.BusinessServiceImpl.*(..))";

    @Around(POINTCUT)
    public Object analysisAround(ProceedingJoinPoint joinPoint) {
        Object obj = null;
        long startTime = System.currentTimeMillis();
        try {
            obj = joinPoint.proceed(joinPoint.getArgs());
        } catch (Throwable e) {	
            logger.error(e.getMessage());
        }
        long endTime = System.currentTimeMillis();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getDeclaringTypeName() + "." + signature.getName();
        long diffTime = endTime - startTime;
        logger.info("-----" + methodName + "执行时间 :" + diffTime + " ms");
        return obj;
    }
}

4、xml配置

<context:component-scan base-package="aop"/>
<aop:aspectj-autoproxy/>

5、主函数调用

public class AopMain {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext f = 
new ClassPathXmlApplicationContext("spring-aop.xml");
        IBusinessService businessService = (IBusinessService) f.getBean("businessService");
        businessService.executeBusinessA();
        businessService.executeBusinessB();

    }
}

6、打印
executing business in methodA
aop.service.IBusinessService.executeBusinessA执行时间 :203 ms
executing business in methodB
aop.service.IBusinessService.executeBusinessB执行时间 :1003 ms

AOP的实现原理?
以上面的AOP实现为例分析AOP的实现原理:
1、@Component
@Component会让Spring将切面类加入Spring的Bean容器;
2、@Aspect
@Aspect告诉Spring该Bean是一个拦截器,Spring就会去其中寻找所有的拦截方法和拦截规则。
3、创建代理
Spring有2种方式创建代理:JDK动态代理和CGLIB代理。
spring选择策略:
(1)如果目标类实现了接口,默认采用jdk动态代理来实现AOP
(2)如果目标类实现了接口,可以通过配置文件强行使用CGLib来实现AOP代理
(3)如果目标类没有实现接口,只能使用CGlib来实现AOP代理。
【注】CGlib可以为那些没有实现接口的类增强行为,原理是为目标类生成一个子类,并覆盖其中的方法

###Spring AOP 的概念 AOP(Aspect-Oriented Programming)即面向切面编程,是一种编程范式,旨在通过分离横切关注点来提高模块化程度。在 Spring 框架中,AOP 被广泛用于实现诸如日志记录、事务管理、安全性等通用功能,这些功能通常与业务逻辑无关但又需要在多个地方重复使用。 Spring AOP 主要是基于 AspectJ 实现的,尽管 AspectJ 是一个独立的 AOP 框架,并不是 Spring 的组成部分,但它通常与 Spring 一起使用以提供更强大的 AOP 功能[^1]。Spring AOP 支持两种方式来定义切面:基于 XML 配置文件的方式和基于注解的方式。 ###Spring AOP 的原理 Spring AOP 使用运行时代理来实现 AOP 功能,这意味着它会在运行时动态生成代理对象。对于实现了接口的类,Spring AOP 默认使用 JDK 动态代理;而对于没有实现接口的类,则会使用 CGLIB 代理[^4]。这种方式允许在不修改原始代码的情况下向程序中添加新的行为。 织入(Weaving)是将增强(advice)应用到目标对象的过程,Spring AOP 在运行时进行织入操作[^3]。当创建了代理对象后,所有对目标对象方法的调用都会被拦截,并且可以插入额外的操作,比如在方法执行前后做一些处理。 ###Spring AOP 的使用教程 要开始使用 Spring AOP,首先需要确保项目中包含了必要的依赖。如果使用 Maven 构建工具,可以在 `pom.xml` 文件中加入如下依赖: ```xml <!-- 引入aop依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` 一旦添加了依赖并刷新了 Maven 项目,就可以开始编写切面了。下面是一个简单的例子,展示如何使用注解来定义一个切面: ```java import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void logBefore(JoinPoint joinPoint) { System.out.println("Method " + joinPoint.getSignature().getName() + " is called."); } } ``` 在这个示例中,`LoggingAspect` 类被标记为 `@Aspect` 和 `@Component` 注解,这样 Spring 就能识别这是一个切面组件。`@Before` 注解指定了在哪些方法上应用前置通知(before advice),这里的表达式表示匹配 `com.example.service` 包下所有的方法。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值