镜头为笔光影为墨,两岸青年在算法时代书写AI叙事新篇章
兄弟们咱å�š Spring 项目的时候是ä¸�是总é�‡åˆ°è¿™äº›ç ´äº‹æ¯�个 Controller 里都è¦�写 Autowired UserService userService æ³¨å…¥ä¸€å¤§å † Service代ç �å�ˆä¹±å�ˆå†—ä½™æƒ³ç»Ÿä¸€åŠ ä¸ª 日志/异常处ç�† 得在æ¯�个 Service 方法里写一é��改起æ�¥è¦�ç–¯å�¶å°”还会手滑把 Service ç±»å��/方法å�� 写错编译ä¸�报错跑起æ�¥æ‰�出问题æ�’查å�Šå¤©ã€‚今天给大家分享个我自己写的 ServiceManager 组件用 Lambda æ��å®šè¿™äº›ç ´äº‹ —— ä¸�用手动注入 Service调用方法åƒ�写公å¼�ä¸€æ ·ç®€å�•还能自动缓å˜ã€�统一处ç�†å¼‚常新手也能秒懂秒用01组件能解决的å®�际问题先说说这组件能解决啥å®�é™…é—®é¢˜ä¸¾ä¸ªæ —å�以å‰�咱调用用户查询æ�¥å�£å¾—这么写//
先注入Service Autowired private UserService userService; //
å†�调用方法 public SerResultUserDTO getUser(Long userId) { try { log.info(开始查用户ID{}, userId); UserDTO user userService.queryUser(userId); log.info(查询æˆ�功结æ�œ{}, user); return SerResult.success(user); } catch (Exception e) { log.error(查询失败, e); return SerResult.fail(查用户出错了); } }å�ˆæ˜¯æ³¨å…¥å�ˆæ˜¯æ—¥å¿—å�ˆæ˜¯ try-catch é‡�å¤�代ç �ä¸€å †ã€‚ç”¨äº† ServiceManager 之å��ç›´æ�¥å†™æˆ�è¿™æ ·public SerResultUserDTO getUser(Long userId) { // 一行æ��å®šä¼ æ–¹æ³•å�‚æ•°å…¶ä»–å…¨å¸®ä½ å�š return ServiceManager.call(UserService::queryUser, userId); }注入没了。日志组件自动打。异常组件自动处ç�†ã€‚爽ä¸�爽02ç»„ä»¶æ ¸å¿ƒé€»è¾‘å¤§ç™½è¯�拆解其å®�这组件就干了 3 ä»¶äº‹ä½ ä¼ ä¸ª Lambda比如 UserService::queryUser å®ƒå¸®ä½ æ‰¾åˆ°å¯¹åº”çš„ Service å®�例把找到的å®�例和方法缓å˜èµ·æ�¥ä¸‹æ¬¡è°ƒç”¨æ›´å¿«ç»Ÿä¸€æ‰§è¡Œæ–¹æ³•顺便把日志ã€�异常处ç�†éƒ½åŒ…了。下é�¢å’±ä¸€æ¥æ¥æ�¥ä»£ç �éƒ½ç»™ä½ è´´å¥½å¤�制过å�»æ”¹æ”¹å°±èƒ½ç”¨ã€‚03å…ˆæ�基础 — 需è¦�çš„ä¾�èµ–å’Œå·¥å…·ç±»é¦–å…ˆå¾—æœ‰å‡ ä¸ªå°�工具ä¸�用自己写直æ�¥å¤�制统一返å›�结æ�œç±»SerResultä¸�管调用æˆ�功还是失败都返å›�å�Œä¸€ä¸ªæ ¼å¼�å‰�端好处ç�†package org.pro.wwcx.ledger.common.dto; import lombok.Data; // æœ�务调用的统一返å›�结æ�œå‰�端拿到就知é�“是æˆ�功还是失败 Data publicclass SerResultT { privateint code; // 200æˆ�功500失败å‰�端一看就懂 private String msg; // æ��示信æ�¯æ¯”如“æ“�作æˆ�功â€�“查ä¸�到用户â€� private T data; // æˆ�功时返å›�的数æ�®æ¯”如用户信æ�¯ // æˆ�功的时候调用这个方法把数æ�®ä¼ è¿›å�» publicstatic T SerResultT success(T data) { SerResultT result new SerResult(); result.setCode(
; result.setMsg(æ“�作æˆ�功); result.setData(data); return result; } // å¤±è´¥çš„æ—¶å€™è°ƒç”¨è¿™ä¸ªæ–¹æ³•ä¼ é”™è¯¯ä¿¡æ�¯ publicstatic T SerResultT fail(String msg) { SerResultT result new SerResult(); result.setCode(
; result.setMsg(msg); result.setData(null); return result; } }Lambda è§£æ��工具LambdaUtilè¿™å·¥å…·æ˜¯æ ¸å¿ƒå¸®å’±ä»� Lambda 里 “扣â€� 出 Service ç±»å��和方法å��ä¸�用懂å�Ÿç�†å¤�制用就行package org.pro.wwcx.ledger.common.util; import java.io.Serializable; import java.lang.reflect.Method; import java.lang.invoke.SerializedLambda; // ä»�Lambda表达å¼�里拿Serviceä¿¡æ�¯çš„工具 publicclass LambdaUtil { // ä¼ ä¸ªLambdaè¿›æ�¥è¿”å›�它对应的“元数æ�®â€�比如哪个Service哪个方法 public static SerializedLambda valueOf(Serializable lambda) { if (lambda null) { thrownew IllegalArgumentException(Lambdaä¸�èƒ½ä¼ ç©º); } try { // å��射拿到Lambda里的éš�è—�方法ä¸�用管这行是咋å›�事 Method writeReplaceMethod lambda.getClass().getDeclaredMethod(writeReplace); writeReplaceMethod.setAccessible(true); return (SerializedLambda) writeReplaceMethod.invoke(lambda); } catch (Exception e) { thrownew RuntimeException(è§£æ��Lambda出错了, e); } } }Spring 工具类SpringUtil帮咱ä»� Spring 里拿 Service å®�例ä¸�用手动 Autowired 就是é� 它package org.pro.wwcx.ledger.common.util; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; // ä»�Spring里拿Bean的工具ä¸�用自己注入Service Component publicclass SpringUtil implements ApplicationContextAware { // Spring的上下文相当äº�“Bean仓库â€� privatestatic ApplicationContext applicationContext; // ä»�仓库里按类å�‹æ‹¿Bean比如拿UserServiceç±»å�‹çš„å®�例 publicstatic T T getBean(ClassT requiredType) { if (applicationContext null) { thrownew RuntimeException(Spring还没åˆ�始化好呢); } return applicationContext.getBean(requiredType); } // 下é�¢è¿™è¡Œæ˜¯Spring自动调用的ä¸�用管 Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringUtil.applicationContext applicationContext; } }函数æ�¥å�£SerialBiFunction这个是 Lambda çš„ “规矩â€�è§„å®šä¼ å�‚和返å›�å€¼çš„æ ¼å¼�å¤�制就行package org.pro.wwcx.ledger.common.resolver.anno; import java.io.Serializable; // 支æŒ�åº�列化的å�Œå�‚数函数æ�¥å�£Lambdaè¦�符å�ˆè¿™ä¸ªæ ¼å¼� public interface SerialBiFunctionT, U, R extends Serializable { // æ–¹æ³•æ ¼å¼�ä¼ å…¥TServiceå®�例和Uå�‚æ•°è¿”å›�R结æ�œ R apply(T t, U u); }å®�例æ�„建器InstBuilder帮咱快速创建对象的å°�工具ä¸�ç”¨å†™ä¸€å †set方法package org.pro.wwcx.ledger.common.resolver; // 快速创建对象的工具比如new ServiceExecutorå��ä¸�用一个个set值 public class InstBuilderT { privatefinal T target; // åˆ�始化è¦�创建的对象 private InstBuilder(ClassT clazz) { try { this.target clazz.getDeclaredConstructor().newInstance(); } catch (Exception e) { thrownew RuntimeException(创建对象失败, e); } } // é�™æ€�方法入å�£InstBuilder.of(ServiceExecutor.class) public static T InstBuilderT of(ClassT clazz) { returnnew InstBuilder(clazz); } // 链å¼�set值比如.set(ServiceExecutor::setParam, param) public V InstBuilderT set(SetterT, V setter, V value) { setter.set(target, value); returnthis; } // 最å��调用build()拿到对象 public T build() { return target; } // 定义setterçš„æ ¼å¼� FunctionalInterface public interface SetterT, V { void set(T target, V value); } }04æ ¸å¿ƒç»„ä»¶ — ServiceManagerè¿™æ˜¯å’±çš„ä¸»è§’æ‰€æœ‰é€»è¾‘éƒ½åœ¨è¿™æˆ‘ä¸€è¡Œè¡Œç»™ä½ è®²æ˜�白package org.pro.wwcx.ledger.common.servicer; import lombok.extern.slf4j.Slf4j; import org.pro.wwcx.ledger.common.dto.SerResult; import org.pro.wwcx.ledger.common.resolver.InstBuilder; import org.pro.wwcx.ledger.common.resolver.anno.SerialBiFunction; import org.pro.wwcx.ledger.common.util.LambdaUtil; import org.pro.wwcx.ledger.common.util.SpringUtil; import java.lang.invoke.SerializedLambda; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; // 日志注解能打日志 Slf4j public class ServiceManager { // 缓å˜åˆ�始化大å°�6666够咱用了ä¸�够å†�改 privatestaticfinalint INIT_COUNT 6666; // 缓å˜Lambda对应的Serviceä¿¡æ�¯key是Lambdavalue是Service元数æ�® privatestaticfinal MapSerialBiFunction?,?,?, LambdaMeta? CACHE_LAMBDA; // é�™æ€�代ç �å�—项目å�¯åŠ¨æ—¶å°±åˆ�å§‹åŒ–ç¼“å˜ static { CACHE_LAMBDA new ConcurrentHashMap(INIT_COUNT); } // 对外æ��ä¾›çš„è°ƒç”¨æ–¹æ³•ä¼ Lambda比如UserService::queryUserå’Œå�‚æ•°è¿”å›�结æ�œ SuppressWarnings(unchecked) public static T,U,R SerResultR call(SerialBiFunctionT,U,R fn, U param){ // 先检查Lambdaä¸�èƒ½ä¼ ç©º if (fn null) { return SerResult.fail(æœ�务函数ä¸�能为空); } //
ä»�ç¼“å˜æ‹¿Serviceä¿¡æ�¯æœ‰å°±ç›´æ�¥ç”¨æ²¡æœ‰å°±è§£æ��å¹¶ç¼“å˜ LambdaMetaT lambdaMeta (LambdaMetaT) CACHE_LAMBDA.computeIfAbsent(fn, k- { // è§£æ��Lambda拿到Serviceå®�例ã€�ç±»å��这些信æ�¯ LambdaMetaT meta parseSerialFunction(fn); log.debug(缓å˜Serviceä¿¡æ�¯{}, meta.getServiceName()); return meta; }); //
创建执行器把Lambdaã€�å�‚æ•°ã€�Serviceä¿¡æ�¯ä¼ è¿›å�» ServiceExecutorT,U,R executor InstBuilder.of(ServiceExecutor.class) .set(ServiceExecutor::setServiceFn, fn) // ä¼ Lambda方法 .set(ServiceExecutor::setParam, param) // ä¼ å�‚æ•° .set(ServiceExecutor::setLambdaMeta, lambdaMeta) // ä¼ Serviceä¿¡æ�¯ .build(); // æ�„建执行器 //
执行方法返�结� return executor.callService(); } // 解�Lambda�Lambda里拿到Service类���例�方法� SuppressWarnings(unchecked) private static T, U, R LambdaMetaT parseSerialFunction(SerialBiFunctionT,U,R fn) { // 用LambdaUtil拿到Lambda的元数� SerializedLambda lambda LambdaUtil.valueOf(fn); // �装Service信�的对象 LambdaMetaT lambdaMeta new LambdaMeta(); //
解�Service类�Lambda里的类�是“com/example/UserService��改�“com.example.UserService� String tClassName lambda.getImplClass().replaceAll(/, .); try { //
拿到Service的Class对象比如UserService.class ClassT aClass (ClassT) Class.forName(tClassName); //
ä»�Spring里拿Serviceå®�例ä¸�用Autowired就是é� 这行 T inst SpringUtil.getBean(aClass); //
把信æ�¯å˜åˆ°lambdaMeta里 lambdaMeta.setClazz(aClass); // å˜Serviceçš„Class lambdaMeta.setInst(inst); // å˜Serviceå®�例 lambdaMeta.setServiceName(lambda.getImplMethodName()); // å˜æ–¹æ³•å��比如queryUser } catch (ClassNotFoundException e) { // 找ä¸�到类就抛异常 thrownew RuntimeException(没找到Serviceç±» tClassName, e); } return lambdaMeta; } // å°�装Serviceä¿¡æ�¯çš„内部类å˜Classã€�å®�例ã€�方法å�� lombok.Data private staticclass LambdaMetaT { private ClassT clazz; // Serviceçš„Class比如UserService.class private T inst; // Serviceå®�例Spring里的Bean private String serviceName; // 方法å��比如queryUser } }05执行器 — ServiceExecutor这是帮咱统一执行方法ã€�打日志ã€�处ç�†å¼‚常的 “打工人â€�package org.pro.wwcx.ledger.common.servicer; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.pro.wwcx.ledger.common.dto.SerResult; import org.pro.wwcx.ledger.common.resolver.anno.SerialBiFunction; // 执行Service方法的类统一打日志ã€�处ç�†å¼‚常 Slf4j Setter publicclass ServiceExecutorT, U, R { private SerialBiFunctionT, U, R serviceFn; // è¦�执行的Lambda方法 private U param; // 方法å�‚æ•° private ServiceManager.LambdaMetaT lambdaMeta; // Serviceä¿¡æ�¯ // æ‰§è¡Œæ–¹æ³•çš„æ ¸å¿ƒé€»è¾‘ public SerResultR callService() { // 记录开始时间方便算耗时 long startTime System.currentTimeMillis(); String serviceName lambdaMeta.getClazz().getSimpleName(); // 比如UserService String methodName lambdaMeta.getServiceName(); // 比如queryUser log.info(开始调用{}çš„{}方法å�‚æ•°{}, serviceName, methodName, param); try { // çœŸæ£æ‰§è¡Œæ–¹æ³•用Serviceå®�例调用Lambda方法 R result serviceFn.apply(lambdaMeta.getInst(), param); // 算耗时打æˆ�功日志 long costTime System.currentTimeMillis() - startTime; log.info(调用æˆ�功{}çš„{}方法耗时{}ms结æ�œ{}, serviceName, methodName, costTime, result); // è¿”å›�æˆ�功结æ�œ return SerResult.success(result); } catch (Exception e) { // 出错了就打错误日志返å›�失败结æ�œ long costTime System.currentTimeMillis() - startTime; log.error(调用失败{}çš„{}方法耗时{}ms, serviceName, methodName, costTime, e); return SerResult.fail(调用 serviceName çš„ methodName 方法失败 e.getMessage()); } } }06æ€�么用举个å®�际例å�咱以用户查询和更新为例看 Controller 里æ€�么写先写个 Serviceæ£å¸¸å†™ä¸�用改package org.pro.wwcx.ledger.service; import org.pro.wwcx.ledger.dto.UserDTO; import org.pro.wwcx.ledger.dto.UserUpdateDTO; import org.springframework.stereotype.Service; // æ£å¸¸çš„Service该咋写咋写 Service publicclass UserService { // æŸ¥ç”¨æˆ·æ ¹æ�®ID查 public UserDTO queryUser(Long userId) { // 这里模拟查数æ�®åº“å®�际项目里æ�¢JDBC/MyBatis UserDTO user new UserDTO(); user.setUserId(userId); user.setUserName(å¼ ä¸‰); user.setAge(
; return user; } // æ›´æ–°ç”¨æˆ·ä¼ ID和更新å�‚æ•° public Boolean updateUser(Long userId, UserUpdateDTO updateDTO) { // 这里模拟更新数æ�®åº“ log.info(更新用户{}的信æ�¯{}, userId, updateDTO); returntrue; // è¿”å›�æ›´æ–°æˆ�功 } }Controller 里调用é‡�点看å�˜åŒ–package org.pro.wwcx.ledger.controller; import org.pro.wwcx.ledger.common.dto.SerResult; import org.pro.wwcx.ledger.common.servicer.ServiceManager; import org.pro.wwcx.ledger.dto.UserDTO; import org.pro.wwcx.ledger.dto.UserUpdateDTO; import org.pro.wwcx.ledger.service.UserService; import org.springframework.web.bind.annotation.*; RestController RequestMapping(/user) publicclass UserController { // 查用户ä¸�用注入UserService一行æ��定 GetMapping(/{userId}) public SerResultUserDTO getUser(PathVariable Long userId) { // ç›´æ�¥ä¼ LambdaUserService::queryUserå’Œå�‚æ•°userId return ServiceManager.call(UserService::queryUser, userId); } // 更新用户å�Œæ ·ä¸�用注入 PutMapping(/{userId}) public SerResultBoolean updateUser( PathVariable Long userId, RequestBody UserUpdateDTO updateDTO) { // 这里è¦�注æ„�å› ä¸ºupdateUser有两个å�‚数所以è¦�显å¼�指定Lambdaç±»å�‹ return ServiceManager.call( (UserService service, UserUpdateDTO dto) - service.updateUser(userId, dto), updateDTO ); } }è·‘èµ·æ�¥çœ‹çœ‹æ•ˆæ�œæŸ¥ç”¨æˆ·çš„æ—¶å€™æ—¥å¿—会自动打开始调用UserServiceçš„queryUser方法å�‚æ•°1001 调用æˆ�功UserServiceçš„queryUser方法耗时5ms结æ�œUserDTO(userId1001, userNameå¼ ä¸‰, age
è¦�æ˜¯å‡ºé”™äº†æ¯”å¦‚ä¼ ä¸ªä¸�å˜åœ¨çš„用户 IDå�‡è®¾æ•°æ�®åº“查ä¸�到会抛异常日志会打错误信æ�¯è¿”å›�ç»™å‰�端的结æ�œæ˜¯{ code: 500, msg: 调用UserServiceçš„queryUser方法失败用户ä¸�å˜åœ¨, data: null }07这组件的好处总结一下ä¸�用å†�写 Autowired Controller 里干干净净å†�也ä¸�ç”¨æ³¨å…¥ä¸€å † Service统一日志 / 异常 æƒ³æ”¹æ—¥å¿—æ ¼å¼�ã€�åŠ æ�ƒé™�æ ¡éªŒå�ªéœ€è¦�改 ServiceExecutor ä¸�用改æ¯�个方法缓å˜ä¼˜åŒ– è§£æ��过的 Service ä¿¡æ�¯ä¼šç¼“å˜ä¸‹æ¬¡è°ƒç”¨æ›´å¿«ç±»å�‹å®‰å…¨ 写 Lambda 的时候方法å��错了编译就报错ä¸�用ç‰åˆ°è¿�行æ‰�å�‘ç�°ã€‚08注æ„�事项é�¿å�‘指å�—JDK 版本 用 JDK8 å�Šä»¥ä¸ŠLambda 表达å¼�是 JDK8 æ‰�有的Service è¦�åŠ Service Spring æ‰�能扫æ��到ä¸�ç„¶ SpringUtil æ‹¿ä¸�到å®�例多å®�ç�°ç±»çš„æƒ…况 如æ�œä¸€ä¸ªæ�¥å�£æœ‰å¤šä¸ªå®�ç�°æ¯”如 UserService 有 UserServiceImpl1 å’Œ UserServiceImpl2 需è¦�在 SpringUtil é‡ŒåŠ æŒ‰å��ç§°æ‹¿ Bean 的方法。
黄瓜视频-黄瓜视频应用