互联网定制网站,长沙建站公司,短视频seo关键词,新乡做网站的多吗目录 面向切面编程AOPAOP的目标#xff1a;让我们可以“专心做事”专心做事专心做事解决方案1.0专心做事解决方案2.0蓝图 AOP应用场景AOP原理AOP相关术语术语理解 AOP案例实现前置/后置/异常/最终增强的配置实现1.依赖2.业务类3.日志类4.配置切入点表达式匹配规则举例 环绕增强… 目录 面向切面编程AOPAOP的目标让我们可以“专心做事”专心做事专心做事解决方案1.0专心做事解决方案2.0蓝图 AOP应用场景AOP原理AOP相关术语术语理解 AOP案例实现前置/后置/异常/最终增强的配置实现1.依赖2.业务类3.日志类4.配置切入点表达式匹配规则举例 环绕增强的配置实现(1替4)1.service类不变2.日志类3.配置 Spring AOP配置元素注解实现AOP1.service类不变2.日志类3.配置 面向切面编程AOP
AOP的目标让我们可以“专心做事”
专心做事
我们作为开发系统可以分为两大部分业务功能和辅助业务的隐性功能。例如开发一个商城系统商品模块的商品添加业务就是业务功能而保证商品添加不出问题如程序在执行商品添加时的入参/出参记录、事务处理等就属于辅助业务的隐性功能通常这些隐性的辅助功能一来都比较通用二来跟业务平没有什么联系。因此就需要考虑将这些通用功能集中处理来简化编码、专心做事。
专心做事解决方案1.0
解决方案把公共代码抽取到一个父类的BaseService让具体的模块Service继承BaseService然后调用父类的功能这样做即通过继承的方式实现对业务方法的功能的增强。如 通用功能类
public class BaseService { // 新增事务public void transaction(){System.out.println(事务功能);} // 入参日志public void before(){System.out.println(记录入参日志功能);}// 出参日志public void afterReturnLog(){System.out.println(记录出参日志功能);}// 资源最终关闭public void afterLog(){System.out.println(资源close功能...);}
}业务类
public class UserServiceImpl extends BaseService{public void save(User user){super.before();super.transaction();// 调用Dao新增用户super.afterReturnLog();super.after();}
}public class GoodsServiceImpl extends BaseService{public void save(Goods goods){super.before();super.transaction();// 调用Dao新增商品super.afterReturnLog();super.after();}
}但是这样做还有一个问题虽然我们其他模块也需要此功能时可以采用继承的方式来做但是一个很严重的问题是我们的业务功能在去调用的时候对业务功能的增强实际上还是硬编码了。还是没有解决方便维护的问题那我们期望能够解决的问题是能否“神不知鬼不觉”的在不改变源代码的情况下去扩展功能呢 答案肯定是可以的那这就是AOP同时这个也是我们学习AOP的原因所在也是AOP的作用所在。
专心做事解决方案2.0
蓝图 如果从系统的横向角度来看我们的日志功能事务功能、资源关闭功能是把系统的各个模块中的各个业务方法在执行之前从前面拦截了好像拿了一把刀把一个完整的苹果切成一半形成了一个切面。这个也就是 面向切面编程 中切面的含义
AOP应用场景
日志记录、性能统计、安全控制、事务处理、异常处理
AOP原理
将复杂的需求分解出不同方面将散布在系统中的公共功能集中解决采用代理机制组装起来运行在不改变原程序的基础上对代码段进行增强处理增加新的功能核心动态代理
AOP相关术语
增强处理/通知Advice 所谓通知/增强是指拦截到 Joinpoint 之后所要做的事情就是通知。说白了就是一段功能性的代码。 前置增强后置增强环绕增强、异常抛出增强、最终增强等类型 切入点Pointcut 切入点就是对连接点中哪些点进行拦截的定义对连接点一般所有方法都可做连接点进行条件筛选。连接点Join Point 连接点就是可以被拦截的点在程序中通常指的是方法在Spring中只支持方法类型的连接点。在其他的地方可能支持类这里记住方法就行了。切面Aspect 是切入点和通知/增强的结合。目标对象Target objectAOP代理AOP proxy织入Weaving 指的是在把增强的方法加入到目标对象切点方法的拥有者来创建新的对象的过程spring采用的是动态代理织入jdk动态代理和子类动态代理都有AspectJ采用编译期织入和类装载织入。
术语理解
用LOL中远古龙BUFF来理解吧比如你现在在蓝色方蓝色方刚刚跟对面打了一波5V5团战1换5蓝色方辅助挂了这个时候已经30分钟后了你们开始去打远古龙打掉远古龙的时候辅助还没有复活因此只有你们四个人获得了远古龙BUFF。
Joint point连接点 在上面的故事里你们四个有了远古龙BUFF就是都能被增强可以看到远古龙BUFF是可以作用在上面所有人的身上因为如果辅助不挂他也会有BUFF。在Spring中这些人就等于可以被增强的方法。Pointcut切点 在上面的故事里只有你们四个有远古龙BUFF但辅助没有。可以看出来Pointcut切点是有条件的Joint point连接点活着的人被增强了。Advice通知/增强 你们四个在打掉远古龙的时候活着那么你们四个就被增强了。Aspect切面 切点和通知的结合上面的切点就是活着的你们四个(四个点)通知是打掉远古龙后获得的BUFF切点有很多连载一起就像一个面一样。
AOP案例实现 前置/后置/异常/最终增强的配置实现
1.依赖 dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.22/versionscopeprovided/scope/dependency!-- aop依赖 --dependencygroupIdorg.aspectj/groupIdartifactIdaspectjweaver/artifactIdversion1.9.6/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-jdbc/artifactIdversion5.1.9.RELEASE/version/dependency2.业务类
Slf4j
Service
public class UserServiceImpl implements UserService {Resourceprivate UserMapper userMapper;Overridepublic Object saveUser(String userName) {//log.info(调用org.aop.service.impl.UserServiceImpl的saveUser()入参是{},user);boolean result userMapper.insertUser(userName) 0;//log.info(调用org.aop.service.impl.UserServiceImpl的saveUser()完毕返回值是{},result);return result;}Overridepublic boolean updateUser(User user) {//log.info(调用org.aop.service.impl.UserServiceImpl的updateUser()入参是{},user);boolean result userMapper.updateUser(user) 0;//log.info(调用org.aop.service.impl.UserServiceImpl的updateUser()完毕返回值是{},result);return result;}
}3.日志类
package org.aop.log;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;import java.util.Arrays;/*** author: zjl* datetime: 2024/3/30* desc:*/
Slf4j
public class MyServiceLogger {//前置增强public void before(JoinPoint jp) {log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。方法入参 Arrays.toString(jp.getArgs()));}//后置增强public void afterReturning(JoinPoint jp, Object result) {log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。方法返回值 result);}//异常处理增强public void afterThrowing(JoinPoint jp, Throwable e) {log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。方法抛出异常 e);}//最终增强public void after(JoinPoint jp) {log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。方法执行完毕。模拟关闭资源...);}4.配置 增强处理类型特 点Before前置增强处理在目标方法前织入增强处理AfterReturning后置增强处理在目标方法正常执行不出现异常后织入增强处理AfterThrowing异常增强处理在目标方法抛出异常后织入增强处理After最终增强处理不论方法是否抛出异常都会在目标方法最后织入增强处理Around环绕增强处理在目标方法的前后都可以织入增强处理
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.2.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.2.xsd!-- 配置相关的AOP --bean idmyServiceLog classorg.aop.log.MyServiceLogger/aop:configaop:pointcut idpointcutexpressionexecution(* org.aop.service..*.*(..)))/aop:aspect refmyServiceLogaop:before methodbeforepointcut-refpointcut/aop:beforeaop:after-returning methodafterReturningpointcut-refpointcut returningresult/aop:after-throwing methodafterThrowing pointcut-refpointcut throwinge/aop:after methodafter pointcut-refpointcut//aop:aspect/aop:config
/beans切入点表达式匹配规则举例
public * addNewUser(entity.User) “*”表示匹配所有类型的返回值。
public void *(entity.User) “*”表示匹配所有方法名。
public void addNewUser(..) “..”表示匹配所有参数个数和类型。
* com.zjl.service.*.*(..)匹配com.zjl.service包下所有类的所有方法。
* com.zjl.service..*.*(..)匹配com.zjl.service包及其子包下所有类的所有方法环绕增强的配置实现(1替4)
1.service类不变
2.日志类
注释掉前面四种增强的方法加入这个环绕增强的方法 public Object around(ProceedingJoinPoint jp) throws Throwable {Object result null;try {log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。方法入参 Arrays.toString(jp.getArgs()));result jp.proceed();log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。方法返回值是 result);}catch (Exception e){log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。发生了异常,异常信息为 e);}finally {log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法进行最终处理比如模拟资源关闭);}return result;}3.配置 !-- 配置相关的AOP --bean idmyServiceLog classorg.aop.log.MyServiceLogger/aop:configaop:pointcut idpointcutexpressionexecution(* org.aop.service..*.*(..)))/aop:aspect refmyServiceLog!--aop:before methodbeforepointcut-refpointcut/aop:beforeaop:after-returning methodafterReturningpointcut-refpointcut returningresult/aop:after-throwing methodafterThrowing pointcut-refpointcut throwinge/aop:after methodafter pointcut-refpointcut/--aop:around methodaround pointcut-refpointcut//aop:aspect/aop:configSpring AOP配置元素
AOP配置元素描 述aop:configAOP配置的顶层元素大多数的aop:*元素必须包含在aop:config元素内aop:pointcut定义切点aop:aspect定义切面aop:after定义最终增强不管被通知的方法是否执行成功aop:after-returning定义after-returning增强aop:after-throwing定义after-throwing增强aop:around定义环绕增强aop:before定义前置增强aop:aspectj-autoproxy启动AspectJ注解驱动的切面
注解实现AOP
1.service类不变
2.日志类
package org.aop.log;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;import java.util.Arrays;/*** author: zjl* datetime: 2024/3/30* desc:*/
Slf4j
Aspect
Component
public class MyServiceLogger {//1.针对service实现类中所有方法记录某个方法在被调用时的入参信息//Before(execution(* org.aop.service..*.*(..)))public void before(JoinPoint jp) {log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。方法入参 Arrays.toString(jp.getArgs()));}//2.针对service实现类中所有方法记录某个方法被调用后的返回值信息//AfterReturning(returning result, pointcut execution(* org.aop.service..*.*(..)))public void afterReturning(JoinPoint jp, Object result) {log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。方法返回值 result);}//AfterThrowing(throwing e, pointcut execution(* org.aop.service..*.*(..)))public void afterThrowing(JoinPoint jp, Throwable e) {log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。方法抛出异常 e);}// After(execution(* org.aop.service..*.*(..)))public void after(JoinPoint jp) {log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。方法执行完毕。模拟关闭资源...);}Around(execution(* org.aop.service..*.*(..)))public Object around(ProceedingJoinPoint jp) throws Throwable {Object result null;try {log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。方法入参 Arrays.toString(jp.getArgs()));result jp.proceed();log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。方法返回值是 result);}catch (Exception e){log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法。发生了异常,异常信息为 e);}finally {log.info(调用 jp.getTarget() 的 jp.getSignature().getName() 方法进行最终处理比如模拟资源关闭);}return result;}
}3.配置
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.2.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.2.xsdcontext:component-scan base-packageorg.aop/aop:aspectj-autoproxy /
/beans