当前位置: 代码网 > it编程>编程语言>Java > SpringBoot中四种AOP实战应用场景及代码实现

SpringBoot中四种AOP实战应用场景及代码实现

2025年05月03日 Java 我要评论
引言面向切面编程(aop)是spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护。在springboot应用中,aop能够帮助我们优雅地解决横切关注点问题,如日志记录、权

引言

面向切面编程(aop)是spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护。在springboot应用中,aop能够帮助我们优雅地解决横切关注点问题,如日志记录、权限控制、性能监控等,这些功能往往贯穿整个应用但又不属于业务核心逻辑。

本文将介绍springboot中4种aop实战应用场景,包括代码实现、核心原理及实践。

场景一:日志记录与性能监控

业务需求

在企业级应用中,我们通常需要:

  • 记录api请求的调用情况
  • 监控方法执行时间,发现性能瓶颈
  • 追踪方法调用的入参和返回结果

实现方案

@aspect
@component
@slf4j
public class loggingaspect {
    
    /**
     * 定义切点:所有controller包下的所有方法
     */
    @pointcut("execution(* com.example.demo.controller.*.*(..))")
    public void controllermethods() {}
    
    /**
     * 环绕通知:记录请求日志和执行时间
     */
    @around("controllermethods()")
    public object logaroundcontrollers(proceedingjoinpoint joinpoint) throws throwable {
        // 获取方法签名
        methodsignature signature = (methodsignature) joinpoint.getsignature();
        string methodname = signature.getname();
        string classname = signature.getdeclaringtypename();
        
        // 记录请求参数
        string params = arrays.tostring(joinpoint.getargs());
        log.info("request to {}.{} with params: {}", classname, methodname, params);
        
        // 记录开始时间
        long starttime = system.currenttimemillis();
        
        // 执行目标方法
        object result;
        try {
            result = joinpoint.proceed();
            
            // 计算执行时间
            long executiontime = system.currenttimemillis() - starttime;
            
            // 记录返回结果和执行时间
            log.info("response from {}.{} ({}ms): {}", 
                    classname, methodname, executiontime, result);
            
            // 记录慢方法
            if (executiontime > 1000) {
                log.warn("slow execution detected! {}.{} took {}ms", 
                        classname, methodname, executiontime);
            }
            
            return result;
        } catch (exception e) {
            // 记录异常信息
            log.error("exception in {}.{}: {}", classname, methodname, e.getmessage(), e);
            throw e;
        }
    }
    
    /**
     * 定义服务层方法切点
     */
    @pointcut("execution(* com.example.demo.service.*.*(..))")
    public void servicemethods() {}
    
    /**
     * 记录服务层方法的关键调用
     */
    @before("servicemethods() && @annotation(logmethod)")
    public void logservicemethod(joinpoint joinpoint, logmethod logmethod) {
        methodsignature signature = (methodsignature) joinpoint.getsignature();
        string methodname = signature.getname();
        
        // 获取参数名
        string[] paramnames = signature.getparameternames();
        object[] args = joinpoint.getargs();
        
        stringbuilder logmessage = new stringbuilder();
        logmessage.append("executing ").append(methodname).append(" with params: {");
        
        for (int i = 0; i < paramnames.length; i++) {
            logmessage.append(paramnames[i]).append("=").append(args[i]);
            if (i < paramnames.length - 1) {
                logmessage.append(", ");
            }
        }
        logmessage.append("}");
        
        // 根据注解设置的级别记录日志
        switch (logmethod.level()) {
            case debug:
                log.debug(logmessage.tostring());
                break;
            case info:
                log.info(logmessage.tostring());
                break;
            case warn:
                log.warn(logmessage.tostring());
                break;
            case error:
                log.error(logmessage.tostring());
                break;
        }
    }
}

/**
 * 自定义日志注解
 */
@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface logmethod {
    loglevel level() default loglevel.info;
    
    public enum loglevel {
        debug, info, warn, error
    }
}

使用示例

@service
public class userservice {
    
    @logmethod(level = logmethod.loglevel.info)
    public user findbyid(long id) {
        // 业务逻辑
        return userrepository.findbyid(id).orelse(null);
    }
    
    @logmethod(level = logmethod.loglevel.warn)
    public void updateuserstatus(long userid, string status) {
        // 更新用户状态
    }
}

扩展:mdc实现请求跟踪

@component
public class requestidfilter implements filter {
    
    @override
    public void dofilter(servletrequest request, servletresponse response, filterchain chain)
            throws ioexception, servletexception {
        try {
            // 为每个请求生成唯一id
            string requestid = uuid.randomuuid().tostring().replace("-", "");
            mdc.put("requestid", requestid);
            
            if (request instanceof httpservletrequest) {
                httpservletrequest httprequest = (httpservletrequest) request;
                // 记录用户信息
                authentication auth = securitycontextholder.getcontext().getauthentication();
                if (auth != null && auth.isauthenticated()) {
                    mdc.put("userid", auth.getname());
                }
                mdc.put("remoteaddr", httprequest.getremoteaddr());
            }
            
            chain.dofilter(request, response);
        } finally {
            // 请求完成后清理mdc
            mdc.clear();
        }
    }
}

场景二:权限控制与安全增强

业务需求

在企业应用中,权限控制是一个常见的需求:

  • 基于角色的接口访问控制
  • 细粒度的操作权限控制
  • 对敏感数据访问的记录

实现方案

首先,创建自定义注解:

@retention(retentionpolicy.runtime)
@target({elementtype.method, elementtype.type})
public @interface requirespermission {
    /**
     * 所需权限编码数组,满足其中任一即可
     */
    string[] value() default {};
    
    /**
     * 权限逻辑类型:and(同时具有所有权限), or(满足任一权限即可)
     */
    logicaltype logical() default logicaltype.or;
    
    public enum logicaltype {
        and, or
    }
}

实现权限切面:

@aspect
@component
@slf4j
public class permissionaspect {
    
    @autowired
    private userservice userservice;
    
    /**
     * 定义切点:所有带有@requirespermission注解的方法
     */
    @pointcut("@annotation(com.example.demo.annotation.requirespermission)")
    public void permissioncheck() {}
    
    /**
     * 权限验证前置通知
     */
    @before("permissioncheck() && @annotation(requirespermission)")
    public void checkpermission(joinpoint joinpoint, requirespermission requirespermission) {
        // 获取当前用户
        user currentuser = getcurrentuser();
        if (currentuser == null) {
            throw new unauthorizedexception("用户未登录或会话已过期");
        }
        
        // 获取用户权限列表
        set<string> userpermissions = userservice.getuserpermissions(currentuser.getid());
        
        // 获取注解中要求的权限
        string[] requiredpermissions = requirespermission.value();
        requirespermission.logicaltype logicaltype = requirespermission.logical();
        
        // 权限校验
        boolean haspermission = false;
        
        if (logicaltype == requirespermission.logicaltype.or) {
            // 满足任一权限即可
            for (string permission : requiredpermissions) {
                if (userpermissions.contains(permission)) {
                    haspermission = true;
                    break;
                }
            }
        } else {
            // 必须同时满足所有权限
            haspermission = true;
            for (string permission : requiredpermissions) {
                if (!userpermissions.contains(permission)) {
                    haspermission = false;
                    break;
                }
            }
        }
        
        if (!haspermission) {
            log.warn("用户 {} 尝试访问未授权资源: {}.{}", 
                    currentuser.getusername(),
                    joinpoint.getsignature().getdeclaringtypename(),
                    joinpoint.getsignature().getname());
            
            throw new forbiddenexception("权限不足,无法执行该操作");
        }
        
        // 记录敏感操作
        log.info("用户 {} 执行了需授权操作: {}.{}", 
                currentuser.getusername(), 
                joinpoint.getsignature().getdeclaringtypename(),
                joinpoint.getsignature().getname());
    }
    
    /**
     * 定义切点:带有@requiresrole注解的方法
     */
    @pointcut("@annotation(com.example.demo.annotation.requiresrole)")
    public void rolecheck() {}
    
    /**
     * 角色检查前置通知
     */
    @before("rolecheck() && @annotation(requiresrole)")
    public void checkrole(joinpoint joinpoint, requiresrole requiresrole) {
        // 获取当前用户
        user currentuser = getcurrentuser();
        if (currentuser == null) {
            throw new unauthorizedexception("用户未登录或会话已过期");
        }
        
        // 获取用户角色
        set<string> userroles = userservice.getuserroles(currentuser.getid());
        
        // 获取注解中要求的角色
        string[] requiredroles = requiresrole.value();
        
        // 角色校验
        boolean hasrole = false;
        for (string role : requiredroles) {
            if (userroles.contains(role)) {
                hasrole = true;
                break;
            }
        }
        
        if (!hasrole) {
            log.warn("用户 {} 尝试访问未授权角色资源: {}.{}", 
                    currentuser.getusername(),
                    joinpoint.getsignature().getdeclaringtypename(),
                    joinpoint.getsignature().getname());
            
            throw new forbiddenexception("角色不足,无法执行该操作");
        }
    }
    
    /**
     * 数据权限过滤切点:针对查询方法
     */
    @pointcut("execution(* com.example.demo.service.*.find*(..))")
    public void datapermissionfilter() {}
    
    /**
     * 数据权限过滤通知
     */
    @around("datapermissionfilter()")
    public object filterdatabypermission(proceedingjoinpoint joinpoint) throws throwable {
        // 获取当前用户
        user currentuser = getcurrentuser();
        
        // 默认情况下执行原方法
        object result = joinpoint.proceed();
        
        // 如果是管理员,无需过滤数据
        if (userservice.isadmin(currentuser.getid())) {
            return result;
        }
        
        // 对查询结果进行过滤
        if (result instanceof collection) {
            collection<?> collection = (collection<?>) result;
            // 实现数据过滤逻辑...
        } else if (result instanceof page) {
            page<?> page = (page<?>) result;
            // 实现分页数据过滤...
        }
        
        return result;
    }
    
    /**
     * 获取当前登录用户
     */
    private user getcurrentuser() {
        authentication authentication = securitycontextholder.getcontext().getauthentication();
        if (authentication == null || !authentication.isauthenticated()) {
            return null;
        }
        
        object principal = authentication.getprincipal();
        if (principal instanceof user) {
            return (user) principal;
        }
        
        return null;
    }
}

/**
 * 自定义角色注解
 */
@retention(retentionpolicy.runtime)
@target({elementtype.method, elementtype.type})
public @interface requiresrole {
    string[] value();
}

使用示例

@restcontroller
@requestmapping("/api/users")
public class usercontroller {
    
    @autowired
    private userservice userservice;
    
    @getmapping
    @requirespermission("user:list")
    public list<user> listusers() {
        return userservice.findall();
    }
    
    @getmapping("/{id}")
    @requirespermission("user:view")
    public user getuser(@pathvariable long id) {
        return userservice.findbyid(id);
    }
    
    @postmapping
    @requirespermission(value = {"user:create", "user:edit"}, logical = requirespermission.logicaltype.or)
    public user createuser(@requestbody user user) {
        return userservice.save(user);
    }
    
    @deletemapping("/{id}")
    @requiresrole("admin")
    public void deleteuser(@pathvariable long id) {
        userservice.delete(id);
    }
    
    @putmapping("/{id}/status")
    @requirespermission(value = {"user:edit", "user:manage"}, logical = requirespermission.logicaltype.and)
    public user updateuserstatus(@pathvariable long id, @requestparam string status) {
        return userservice.updatestatus(id, status);
    }
}

场景三:自定义缓存实现

业务需求

缓存是提升应用性能的关键手段,通过aop可以实现:

  • 自定义缓存策略,满足特定业务需求
  • 细粒度的缓存控制
  • 灵活的缓存键生成和过期策略

实现方案

首先定义缓存注解:

@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface cacheable {
    /**
     * 缓存名称
     */
    string cachename();
    
    /**
     * 缓存键表达式,支持spel表达式
     */
    string key() default "";
    
    /**
     * 过期时间(秒)
     */
    long expiretime() default 300;
    
    /**
     * 是否使用方法参数作为缓存键的一部分
     */
    boolean usemethodparameters() default true;
}

@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface cacheevict {
    /**
     * 缓存名称
     */
    string cachename();
    
    /**
     * 缓存键表达式
     */
    string key() default "";
    
    /**
     * 是否清除所有缓存
     */
    boolean allentries() default false;
}

实现缓存切面:

@aspect
@component
@slf4j
public class cacheaspect {
    
    @autowired
    private redistemplate<string, object> redistemplate;
    
    @autowired
    private cachekeygenerator keygenerator;
    
    /**
     * 定义缓存获取切点
     */
    @pointcut("@annotation(com.example.demo.annotation.cacheable)")
    public void cacheableoperation() {}
    
    /**
     * 定义缓存清除切点
     */
    @pointcut("@annotation(com.example.demo.annotation.cacheevict)")
    public void cacheevictoperation() {}
    
    /**
     * 缓存环绕通知
     */
    @around("cacheableoperation() && @annotation(cacheable)")
    public object handlecacheable(proceedingjoinpoint joinpoint, cacheable cacheable) throws throwable {
        // 生成缓存键
        string cachekey = generatecachekey(joinpoint, cacheable.cachename(), cacheable.key(), cacheable.usemethodparameters());
        
        // 检查缓存中是否已有数据
        boolean haskey = redistemplate.haskey(cachekey);
        if (boolean.true.equals(haskey)) {
            object cachedvalue = redistemplate.opsforvalue().get(cachekey);
            log.debug("cache hit for key: {}", cachekey);
            return cachedvalue;
        }
        
        // 缓存未命中,执行方法获取结果
        log.debug("cache miss for key: {}", cachekey);
        object result = joinpoint.proceed();
        
        // 将结果存入缓存
        if (result != null) {
            redistemplate.opsforvalue().set(cachekey, result, cacheable.expiretime(), timeunit.seconds);
            log.debug("stored in cache with key: {}, expire time: {}s", cachekey, cacheable.expiretime());
        }
        
        return result;
    }
    
    /**
     * 缓存清除前置通知
     */
    @before("cacheevictoperation() && @annotation(cacheevict)")
    public void handlecacheevict(joinpoint joinpoint, cacheevict cacheevict) {
        if (cacheevict.allentries()) {
            // 清除该缓存名称下的所有条目
            string cachepattern = cacheevict.cachename() + ":*";
            set<string> keys = redistemplate.keys(cachepattern);
            if (keys != null && !keys.isempty()) {
                redistemplate.delete(keys);
                log.debug("cleared all cache entries with pattern: {}", cachepattern);
            }
        } else {
            // 清除指定键的缓存
            string cachekey = generatecachekey(joinpoint, cacheevict.cachename(), cacheevict.key(), true);
            redistemplate.delete(cachekey);
            log.debug("cleared cache with key: {}", cachekey);
        }
    }
    
    /**
     * 生成缓存键
     */
    private string generatecachekey(joinpoint joinpoint, string cachename, string keyexpression, boolean useparams) {
        stringbuilder keybuilder = new stringbuilder(cachename).append(":");
        
        // 如果提供了自定义键表达式
        if (stringutils.hastext(keyexpression)) {
            string evaluatedkey = keygenerator.generatekey(keyexpression, joinpoint);
            keybuilder.append(evaluatedkey);
        } else if (useparams) {
            // 使用方法签名和参数作为键
            methodsignature signature = (methodsignature) joinpoint.getsignature();
            string methodname = signature.getname();
            keybuilder.append(methodname);
            
            // 添加参数
            object[] args = joinpoint.getargs();
            if (args != null && args.length > 0) {
                for (object arg : args) {
                    if (arg != null) {
                        keybuilder.append(":").append(arg.hashcode());
                    } else {
                        keybuilder.append(":null");
                    }
                }
            }
        } else {
            // 仅使用方法名
            keybuilder.append(joinpoint.getsignature().getname());
        }
        
        return keybuilder.tostring();
    }
}

/**
 * 缓存键生成器,支持spel表达式
 */
@component
public class cachekeygenerator {
    
    private final expressionparser parser = new spelexpressionparser();
    private final standardevaluationcontext context = new standardevaluationcontext();
    
    public string generatekey(string expression, joinpoint joinpoint) {
        methodsignature signature = (methodsignature) joinpoint.getsignature();
        method method = signature.getmethod();
        object[] args = joinpoint.getargs();
        string[] parameternames = signature.getparameternames();
        
        // 设置方法参数为上下文变量
        for (int i = 0; i < parameternames.length; i++) {
            context.setvariable(parameternames[i], args[i]);
        }
        
        // 添加额外的元数据
        context.setvariable("method", method.getname());
        context.setvariable("class", method.getdeclaringclass().getsimplename());
        context.setvariable("target", joinpoint.gettarget());
        
        // 执行表达式
        expression exp = parser.parseexpression(expression);
        return exp.getvalue(context, string.class);
    }
}

redis配置

@configuration
public class redisconfig {
    
    @bean
    public redistemplate<string, object> redistemplate(redisconnectionfactory connectionfactory) {
        redistemplate<string, object> template = new redistemplate<>();
        template.setconnectionfactory(connectionfactory);
        
        // 使用jackson2jsonredisserializer序列化值
        jackson2jsonredisserializer<object> jackson2jsonredisserializer = new jackson2jsonredisserializer<>(object.class);
        objectmapper om = new objectmapper();
        om.setvisibility(propertyaccessor.all, jsonautodetect.visibility.any);
        om.activatedefaulttyping(laissezfairesubtypevalidator.instance, objectmapper.defaulttyping.non_final);
        jackson2jsonredisserializer.setobjectmapper(om);
        
        // 设置键的序列化方式为字符串
        template.setkeyserializer(new stringredisserializer());
        // 值使用json序列化
        template.setvalueserializer(jackson2jsonredisserializer);
        
        // hash键也使用字符串
        template.sethashkeyserializer(new stringredisserializer());
        // hash值使用json序列化
        template.sethashvalueserializer(jackson2jsonredisserializer);
        
        template.afterpropertiesset();
        return template;
    }
}

使用示例

@service
public class productservice {
    
    @autowired
    private productrepository productrepository;
    
    @cacheable(cachename = "products", expiretime = 3600)
    public product getbyid(long id) {
        return productrepository.findbyid(id).orelse(null);
    }
    
    @cacheable(cachename = "products", key = "'list:category:' + #categoryid", expiretime = 1800)
    public list<product> getbycategory(long categoryid) {
        return productrepository.findbycategoryid(categoryid);
    }
    
    @cacheevict(cachename = "products", allentries = true)
    public product save(product product) {
        return productrepository.save(product);
    }
    
    @cacheevict(cachename = "products", key = "'list:category:' + #product.categoryid")
    public void deleteproductfromcategory(product product) {
        productrepository.delete(product);
    }
}

场景四:统一异常处理与重试机制

业务需求

在分布式系统或复杂业务场景中,我们常常需要:

  • 优雅地处理异常
  • 对某些操作进行自动重试
  • 对关键操作进行幂等性保证

实现方案

首先定义重试和异常处理注解:

@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface retryable {
    /**
     * 最大重试次数
     */
    int maxattempts() default 3;
    
    /**
     * 重试间隔(毫秒)
     */
    long backoff() default 1000;
    
    /**
     * 指定捕获的异常类型
     */
    class<? extends throwable>[] value() default {exception.class};
    
    /**
     * 重试策略
     */
    retrystrategy strategy() default retrystrategy.fixed;
    
    /**
     * 重试策略枚举
     */
    enum retrystrategy {
        /**
         * 固定间隔
         */
        fixed,
        
        /**
         * 指数退避
         */
        exponential
    }
}

@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface idempotent {
    /**
     * 幂等键表达式
     */
    string key();
    
    /**
     * 过期时间(秒)
     */
    long expireseconds() default 300;
}

实现异常处理和重试切面:

@aspect
@component
@slf4j
public class retryaspect {
    
    @autowired
    private redistemplate<string, string> redistemplate;
    
    /**
     * 定义可重试操作切点
     */
    @pointcut("@annotation(com.example.demo.annotation.retryable)")
    public void retryableoperation() {}
    
    /**
     * 定义幂等操作切点
     */
    @pointcut("@annotation(com.example.demo.annotation.idempotent)")
    public void idempotentoperation() {}
    
    /**
     * 重试环绕通知
     */
    @around("retryableoperation() && @annotation(retryable)")
    public object handleretry(proceedingjoinpoint joinpoint, retryable retryable) throws throwable {
        int attempts = 0;
        class<? extends throwable>[] retryableexceptions = retryable.value();
        retryable.retrystrategy strategy = retryable.strategy();
        
        while (true) {
            attempts++;
            try {
                // 执行目标方法
                return joinpoint.proceed();
            } catch (throwable t) {
                // 检查是否是需要重试的异常类型
                boolean shouldretry = false;
                for (class<? extends throwable> exceptiontype : retryableexceptions) {
                    if (exceptiontype.isinstance(t)) {
                        shouldretry = true;
                        break;
                    }
                }
                
                // 如果不需要重试,或者达到最大重试次数,则抛出异常
                if (!shouldretry || attempts >= retryable.maxattempts()) {
                    log.warn("method {} failed after {} attempts: {}", 
                            joinpoint.getsignature().getname(), attempts, t.getmessage());
                    throw t;
                }
                
                // 计算重试等待时间
                long waittime;
                if (strategy == retryable.retrystrategy.exponential) {
                    // 指数退避: 基础时间 * 2^(尝试次数-1)
                    waittime = retryable.backoff() * (long) math.pow(2, attempts - 1);
                } else {
                    // 固定间隔
                    waittime = retryable.backoff();
                }
                
                log.info("retrying {} (attempt {}/{}) after {} ms due to: {}", 
                        joinpoint.getsignature().getname(), 
                        attempts, 
                        retryable.maxattempts(), 
                        waittime, 
                        t.getmessage());
                
                // 等待指定时间后重试
                thread.sleep(waittime);
            }
        }
    }
    
    /**
     * 幂等性环绕通知
     */
    @around("idempotentoperation() && @annotation(idempotent)")
    public object handleidempotent(proceedingjoinpoint joinpoint, idempotent idempotent) throws throwable {
        // 解析幂等键
        string idempotentkey = resolveidempotentkey(joinpoint, idempotent.key());
        string lockkey = "idempotent:" + idempotentkey;
        
        // 尝试设置分布式锁
        boolean success = redistemplate.opsforvalue().setifabsent(
                lockkey, "processing", idempotent.expireseconds(), timeunit.seconds);
        
        if (boolean.true.equals(success)) {
            try {
                // 获取锁成功,执行业务逻辑
                object result = joinpoint.proceed();
                
                // 将结果存入redis
                string resultkey = "result:" + lockkey;
                redistemplate.opsforvalue().set(
                        resultkey, new objectmapper().writevalueasstring(result), 
                        idempotent.expireseconds(), timeunit.seconds);
                
                // 标记为已处理
                redistemplate.opsforvalue().set(
                        lockkey, "completed", idempotent.expireseconds(), timeunit.seconds);
                
                return result;
            } catch (throwable t) {
                // 处理失败,标记错误
                redistemplate.opsforvalue().set(
                        lockkey, "error:" + t.getmessage(), idempotent.expireseconds(), timeunit.seconds);
                throw t;
            }
        } else {
            // 获取锁失败,表示操作正在处理或已处理
            string status = redistemplate.opsforvalue().get(lockkey);
            
            if ("processing".equals(status)) {
                // 还在处理中
                throw new concurrentoperationexception("操作正在处理中,请勿重复提交");
            } else if (status != null && status.startswith("error:")) {
                // 之前处理出错
                throw new operationfailedexception("操作处理失败: " + status.substring(6));
            } else if ("completed".equals(status)) {
                // 已完成,尝试返回之前的结果
                string resultkey = "result:" + lockkey;
                string resultjson = redistemplate.opsforvalue().get(resultkey);
                
                if (resultjson != null) {
                    // 将json反序列化为响应对象
                    method method = ((methodsignature) joinpoint.getsignature()).getmethod();
                    class<?> returntype = method.getreturntype();
                    
                    try {
                        return new objectmapper().readvalue(resultjson, returntype);
                    } catch (exception e) {
                        log.error("failed to deserialize cached result: {}", e.getmessage());
                    }
                }
                
                // 如果没有找到结果或反序列化失败,返回成功但无法提供上次结果的消息
                throw new operationalreadycompletedexception("操作已成功处理,但无法提供上次操作的结果");
            }
            
            // 状态未知,抛出异常
            throw new operationfailedexception("操作状态未知");
        }
    }
    
    /**
     * 解析幂等键表达式
     */
    private string resolveidempotentkey(joinpoint joinpoint, string keyexpression) {
        methodsignature signature = (methodsignature) joinpoint.getsignature();
        string[] paramnames = signature.getparameternames();
        object[] args = joinpoint.getargs();
        
        // 创建表达式上下文
        standardevaluationcontext context = new standardevaluationcontext();
        
        // 添加方法参数
        for (int i = 0; i < paramnames.length; i++) {
            context.setvariable(paramnames[i], args[i]);
        }
        
        // 添加类名和方法名
        context.setvariable("method", signature.getmethod().getname());
        context.setvariable("class", signature.getdeclaringtype().getsimplename());
        
        // 解析表达式
        expressionparser parser = new spelexpressionparser();
        expression expression = parser.parseexpression(keyexpression);
        
        return expression.getvalue(context, string.class);
    }
}

// 自定义异常类
public class concurrentoperationexception extends runtimeexception {
    public concurrentoperationexception(string message) {
        super(message);
    }
}

public class operationfailedexception extends runtimeexception {
    public operationfailedexception(string message) {
        super(message);
    }
}

public class operationalreadycompletedexception extends runtimeexception {
    public operationalreadycompletedexception(string message) {
        super(message);
    }
}

使用示例

@service
public class paymentservice {
    
    @autowired
    private paymentgateway paymentgateway;
    
    @autowired
    private orderrepository orderrepository;
    
    /**
     * 远程支付处理,可能遇到网络问题需要重试
     */
    @retryable(
        value = {connectexception.class, timeoutexception.class, paymentgatewayexception.class},
        maxattempts = 3,
        backoff = 2000,
        strategy = retryable.retrystrategy.exponential
    )
    public paymentresult processpayment(string orderid, bigdecimal amount) {
        log.info("processing payment for order {} with amount {}", orderid, amount);
        
        // 调用远程支付网关
        return paymentgateway.processpayment(orderid, amount);
    }
    
    /**
     * 订单退款,需要保证幂等性
     */
    @idempotent(key = "'refund:' + #orderid", expireseconds = 3600)
    public refundresult refundorder(string orderid) {
        order order = orderrepository.findbyid(orderid)
                .orelsethrow(() -> new ordernotfoundexception("order not found: " + orderid));
        
        // 验证订单状态
        if (!"paid".equals(order.getstatus())) {
            throw new invalidorderstatusexception("cannot refund order with status: " + order.getstatus());
        }
        
        // 调用支付网关退款
        refundresult result = paymentgateway.refund(order.getpaymentid(), order.gettotalamount());
        
        // 更新订单状态
        order.setstatus("refunded");
        order.setrefundtime(localdatetime.now());
        orderrepository.save(order);
        
        return result;
    }
}

@service
public class stockservice {
    
    @autowired
    private stockrepository stockrepository;
    
    /**
     * 扣减库存,需要在分布式环境下重试和幂等
     */
    @retryable(
        value = {optimisticlockexception.class, stockinsufficientexception.class},
        maxattempts = 5,
        backoff = 500
    )
    @idempotent(key = "'deduct:' + #orderid")
    public void deductstock(string orderid, list<orderitem> items) {
        // 检查是否存在库存记录
        for (orderitem item : items) {
            stock stock = stockrepository.findbyproductid(item.getproductid());
            
            if (stock == null) {
                throw new productnotfoundexception("product not found: " + item.getproductid());
            }
            
            if (stock.getavailable() < item.getquantity()) {
                throw new stockinsufficientexception(
                        "insufficient stock for product: " + item.getproductid() +
                        ", requested: " + item.getquantity() +
                        ", available: " + stock.getavailable());
            }
        }
        
        // 执行库存扣减
        for (orderitem item : items) {
            stockrepository.deductstock(item.getproductid(), item.getquantity());
        }
    }
}

结论

aop是springboot中一个强大的编程范式,通过这些模式,我们可以将横切关注点与业务逻辑解耦,使代码更加模块化、可维护,同时提高系统的健壮性和安全性。

以上就是springboot中四种aop实战应用场景及代码实现的详细内容,更多关于springboot aop应用场景的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com