学习AOP

本文探讨了在HTTP请求处理过程中如何运用AOP(面向切面编程)思想,通过重写不可直接修改的方法如getParameter(),并在Tomcat环境下利用HttpServletRequestWrapper作为代理实现功能增强。

今天看到了这样的代码

在http请求中,重写了getParameter(),这里面用到的就是Aop的思想了。

重写这些不可改变的实现,这里面我们没法去重写类,再去让tomcat来调用我们新写的类,这里就只有使用代理

 

 

在tomcat中已经有写好的代理了HttpServletRequestWrapper.

 

【电能质量扰动】基于ML和DWT的电能质量扰动分类方法研究(Matlab实现)内容概要:本文研究了一种基于机器学习(ML)和离散小波变换(DWT)的电能质量扰动分类方法,并提供了Matlab实现方案。首先利用DWT对电能质量信号进行多尺度分解,提取信号的时频域特征,有效捕捉电压暂降、暂升、中断、谐波、闪变等常见扰动的关键信息;随后结合机器学习分类器(如SVM、BP神经网络等)对提取的特征进行训练与分类,实现对不同类型扰动的自动识别与准确区分。该方法充分发挥DWT在信号去噪与特征提取方面的优势,结合ML强大的模式识别能力,提升了分类精度与鲁棒性,具有较强的实用价值。; 适合人群:电气工程、自动化、电力系统及其自动化等相关专业的研究生、科研人员及从事电能质量监测与分析的工程技术人员;具备一定的信号处理基础和Matlab编程能力者更佳。; 使用场景及目标:①应用于智能电网中的电能质量在线监测系统,实现扰动类型的自动识别;②作为高校或科研机构在信号处理、模式识别、电力系统分析等课程的教学案例或科研实验平台;③目标是提高电能质量扰动分类的准确性与效率,为后续的电能治理与设备保护提供决策依据。; 阅读建议:建议读者结合Matlab代码深入理解DWT的实现过程与特征提取步骤,重点关注小波基选择、分解层数设定及特征向量构造对分类性能的影响,并尝试对比不同机器学习模型的分类效果,以全面掌握该方法的核心技术要点。
<think> 我们要详细学习AOP(面向切面编程)。AOP是一种编程范式,旨在将横切关注点(如日志、事务、安全等)与核心业务逻辑分离,以提高代码的模块化。 常见的AOP实现方式有动态代理、字节码增强等。在Java中,Spring AOP和AspectJ是两个流行的实现。 主要内容包括: 1. AOP核心概念:切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)、引入(Introduction)、目标对象(Target Object)、AOP代理(AOP Proxy)、织入(Weaving) 2. 通知类型:前置通知(Before)、后置通知(After)、返回通知(AfterReturning)、异常通知(AfterThrowing)、环绕通知(Around) 3. 使用Spring AOP和AspectJ的示例 下面我们通过一个Spring AOP的示例来详细说明。 假设我们有一个简单的用户服务,我们想为它的方法添加日志记录。 步骤1:添加依赖(Maven项目) ```xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> artifactId>spring-boot-starter-aop</artifactId> </dependency> </dependencies> ``` 步骤2:定义业务接口和实现 ```java public interface UserService { void addUser(String username); void deleteUser(String username); } @Service public class UserServiceImpl implements UserService { @Override public void addUser(String username) { System.out.println("添加用户: " + username); } @Override public void deleteUser(String username) { System.out.println("删除用户: " + username); } } ``` 步骤3:定义切面 ```java import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { // 定义切点,匹配UserService的所有方法 @Pointcut("execution(* com.example.service.UserService.*(..))") private void userServiceMethods() {} // 前置通知 @Before("userServiceMethods()") public void logBefore(JoinPoint joinPoint) { System.out.println("方法执行前: " + joinPoint.getSignature().getName()); } // 后置通知(无论方法是否成功完成) @After("userServiceMethods()") public void logAfter(JoinPoint joinPoint) { System.out.println("方法执行后: " + joinPoint.getSignature().getName()); } // 返回通知 @AfterReturning(pointcut="userServiceMethods()", returning="retVal") public void logAfterReturning(JoinPoint joinPoint, Object retVal) { System.out.println("方法返回: " + joinPoint.getSignature().getName() + ", 返回值: " + retVal); } // 异常通知 @AfterThrowing(pointcut="userServiceMethods()", throwing="ex") public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) { System.out.println("方法异常: " + joinPoint.getSignature().getName() + ", 异常: " + ex.getMessage()); } // 环绕通知 @Around("userServiceMethods()") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("环绕通知 - 方法执行前: " + joinPoint.getSignature().getName()); Object result = joinPoint.proceed(); // 继续执行方法 System.out.println("环绕通知 - 方法执行后: " + joinPoint.getSignature().getName()); return result; } } ``` 步骤4:测试 ```java @SpringBootApplication public class Application implements CommandLineRunner { @Autowired private UserService userService; public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Override public void run(String... args) throws Exception { userService.addUser("Alice"); userService.deleteUser("Bob"); } } ``` 运行后,控制台将输出类似如下内容: ``` 环绕通知 - 方法执行前: addUser 方法执行前: addUser 添加用户: Alice 环绕通知 - 方法执行后: addUser 方法执行后: addUser 方法返回: addUser, 返回值: null 环绕通知 - 方法执行前: deleteUser 方法执行前: deleteUser 删除用户: Bob 环绕通知 - 方法执行后: deleteUser 方法执行后: deleteUser 方法返回: deleteUser, 返回值: null ``` 解释: - 切点(Pointcut):通过表达式定义哪些方法需要被增强。上面的切点匹配了UserService接口的所有方法。 - 通知(Advice):在切点执行的动作。上面的例子包含了五种通知类型。 - 环绕通知(Around)可以控制方法的执行,可以在方法执行前后添加自定义行为,甚至可以决定是否执行方法。 注意:多个通知的执行顺序 1. 正常情况下:@Around(前半部分)-> @Before -> 方法执行 -> @Around(后半部分)-> @After -> @AfterReturning 2. 出现异常时:@Around(前半部分)-> @Before -> 方法抛出异常 -> @After -> @AfterThrowing 关于切点表达式: - execution:用于匹配方法执行 - 格式:execution(修饰符? 返回类型 类路径? 方法名(参数) 异常?) - 示例:execution(* com.example.service.*.*(..)) 匹配service包下所有类的所有方法 除了execution,还有其他指示符: - within:匹配指定包或类 - within(com.example.service.*) - this:匹配实现指定接口的代理对象 - target:匹配实现指定接口的目标对象 - args:匹配参数类型 - @annotation:匹配带有指定注解的方法 此外,还可以使用逻辑运算符(&&, ||, !)组合多个切点。 总结: AOP通过分离横切关注点,使得业务逻辑更加清晰,减少了重复代码。Spring AOP基于动态代理(JDK动态代理和CGLIB)实现,而AspectJ提供了更强大的功能(如编译时织入)。 §§相关问题§§: 1. Spring AOP和AspectJ有什么区别和联系? 2. 在哪些场景下应该使用环绕通知(Around)而不是其他通知? 3. 如何自定义注解并通过AOP实现方法级别的日志记录? 4. AOP中的切点表达式有哪些常用写法?请举例说明。 </think> ### 详细学习 AOP(面向切面编程) #### 一、AOP 核心概念 1. **切面(Aspect)**:横切关注点的模块化(如日志、事务) 2. **连接点(Joinpoint)**:程序执行点(方法调用、异常抛出) 3. **通知(Advice)**:切面在连接点的执行动作 4. **切入点(Pointcut)**:匹配连接点的表达式 5. **织入(Weaving)**:将切面应用到目标对象的过程 #### 二、通知类型 | 类型 | 执行时机 | 应用场景 | |------|----------|----------| | @Before | 方法执行前 | 权限校验 | | @After | 方法执行后 | 清理资源 | | @AfterReturning | 方法返回后 | 日志记录 | | @AfterThrowing | 异常抛出时 | 异常处理 | | @Around | 方法前后 | 性能监控 | #### 三、Spring AOP 实现(基于代理) ```java // 1. 添加依赖(Maven) <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> // 2. 定义切面 @Aspect @Component public class LoggingAspect { // 3. 定义切入点(匹配service包下的所有方法) @Pointcut("execution(* com.example.service.*.*(..))") public void serviceMethods() {} // 4. 前置通知 @Before("serviceMethods()") public void logBefore(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("准备执行: " + methodName); } // 5. 环绕通知(性能监控) @Around("serviceMethods()") public Object monitorPerformance(ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); Object result = pjp.proceed(); // 执行目标方法 long duration = System.currentTimeMillis() - start; System.out.println(pjp.getSignature() + " 执行时间: " + duration + "ms"); return result; } // 6. 异常通知 @AfterThrowing(pointcut = "serviceMethods()", throwing = "ex") public void logException(JoinPoint jp, Exception ex) { System.err.println("异常方法: " + jp.getSignature()); System.err.println("异常信息: " + ex.getMessage()); } } ``` #### 四、AspectJ 注解详解 ```java // 切入点表达式示例 @Pointcut("execution(public * *(..))") // 所有公共方法 @Pointcut("within(com.xyz.service..*)") // service包及其子包 @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)") // 带有@Transactional注解的方法 @Pointcut("args(java.io.Serializable)") // 单个可序列化参数 @Pointcut("bean(*Service)") // 名称以Service结尾的Bean // 获取上下文信息 @Before("serviceMethods()") public void logParams(JoinPoint jp) { // 获取方法参数 Object[] args = jp.getArgs(); // 获取目标对象 Object target = jp.getTarget(); // 获取代理对象 Object proxy = jp.getThis(); } ``` #### 五、实际应用:事务管理 ```java @Aspect @Component public class TransactionAspect { @Autowired private PlatformTransactionManager transactionManager; @Around("@annotation(transactional)") public Object manageTransaction(ProceedingJoinPoint pjp, Transactional transactional) throws Throwable { TransactionDefinition txDef = new DefaultTransactionDefinition( transactional.propagation().value(), transactional.isolation().value() ); TransactionStatus status = transactionManager.getTransaction(txDef); try { Object result = pjp.proceed(); // 执行目标方法 transactionManager.commit(status); return result; } catch (Exception ex) { transactionManager.rollback(status); throw ex; } } } ``` #### 六、AOP 实现原理 1. **JDK 动态代理**(基于接口) ```java public class JdkDynamicProxy implements InvocationHandler { private final Object target; public JdkDynamicProxy(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) { // 前置增强 Object result = method.invoke(target, args); // 后置增强 return result; } } ``` 2. **CGLIB 字节码增强**(基于子类) ```java public class CglibProxy implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) { // 前置增强 Object result = proxy.invokeSuper(obj, args); // 后置增强 return result; } } ``` #### 七、最佳实践 1. **切面排序**:使用 `@Order` 注解控制切面执行顺序 2. **性能优化**:避免在 `Pointcut` 中使用复杂逻辑 3. **异常处理**:在 `@Around` 中重新抛出异常 4. **线程安全**:避免在切面中保存状态 > **注意**:Spring AOP 只能作用于 Spring 管理的 Bean,对非 public 方法无效,且不支持静态方法拦截。如需更强大功能,考虑使用 AspectJ 编译时织入。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值