聊聊如何让你的业务代码具有可扩展性
前言
在我们开发过程中,会经常碰到这么一些需求,比如在在主流程执行前,要做一些前置事件,在主流程执行之后,做一些收尾工作。对一些新手程序员,他可能会直接写类似如下的代码 public void execute(){ doBefore(); doBiz(); doAfter(); } 复制代码
对有一定工作经验的程序员,他可能会用AOP或者用一些设计模式比如模板模式。那我们今天来聊聊下使用spring + spi + aop + 责任链来实现上面的需求代码实现过程分析
假设主流程只需做一次前置处理和一次后置处理,则伪代码如下 public void execute(){ doBefore(); doBiz(); doAfter(); } 复制代码
此时我们可以用模板模式或者AOP,这边我们采用AOP。其伪代码如下public class CorMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { try { doBefore(); Object result = invocation.proceed(); return result; } catch (Throwable throwable) { log.error("{}",e); } finally { doAfter(); } return null } } 复制代码
如果对这种写法不适应,可以采用@Aspect + @Around方式,效果一个样。
当主流程需要多次前置处理和多次后置处理时,我们的代码可能就变成public class CorMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { try { doBefore(); doBefore(); doBefore(); .... Object result = invocation.proceed(); return result; } catch (Throwable throwable) { log.error("{}",e); } finally { doAfter(); doAfter(); doAfter(); ... } return null } } 复制代码
此时这些前置处理或者后置处理看起来就像是一条链,于是我们就可以考虑采用一些设计模式比如责任链或者采用管道模式。本示例我们使用责任链模式代码实现
1、创建处理器接口public interface AbstarctHandler extends Ordered { /** * 预处理回调,实现服务的预处理 * @return true表示流程继续,false表示流程中断,不会继续调用其他处理器或者服务 */ default boolean preHandler(Invocation invocation){ return true; } /** * 整个请求处理完毕回调方法。类似try-catch-finally中的finally。多个afterCompletion按倒叙输出 */ default void afterCompletion(Invocation invocation){} } 复制代码
2、创建处理器链public class MethodInterceptorChain { private final List abstarctHandlers = new ArrayList<>(); public void addHandler(AbstarctHandler handler){ abstarctHandlers.add(handler); } public List getHanlders(){ if(CollectionUtils.isEmpty(abstarctHandlers)){ return Collections.emptyList(); } AnnotationAwareOrderComparator.sort(abstarctHandlers); return Collections.unmodifiableList(abstarctHandlers); } } 复制代码
3、业务逻辑和责任链整合@Data @AllArgsConstructor @NoArgsConstructor public class CorHandlerInterceptor { private MethodInterceptorChain chain; public Object invoke(Invocation invocation) throws Exception { List abstarctHandlers = chain.getHanlders(); if(CollectionUtils.isEmpty(abstarctHandlers)){ invocation.invoke(); } boolean isCanExec = true; int canExecCount = 0; for (AbstarctHandler abstarctHandler : abstarctHandlers) { canExecCount++; if(!abstarctHandler.preHandler(invocation)){ isCanExec = false; break; } } try{ if(isCanExec){ return invocation.invoke(); } }catch (Exception e){ throw new Exception(e); }finally { for (int i = 0; i < canExecCount; i++) { int j = canExecCount - i - 1; abstarctHandlers.get(j).afterCompletion(invocation); } } return null; } } 复制代码
4、创建AOP切面public class CorMethodInterceptor implements MethodInterceptor { private CorHandlerInterceptor corHandlerInterceptor; public CorMethodInterceptor(CorHandlerInterceptor corHandlerInterceptor) { this.corHandlerInterceptor = corHandlerInterceptor; } @Override public Object invoke(MethodInvocation invocation) throws Throwable { Invocation invoker = Invocation.builder() .args(invocation.getArguments()) .method(invocation.getMethod()) .target(invocation.getThis()).build(); return corHandlerInterceptor.invoke(invoker); } } 复制代码
5、配置切点 @Bean @ConditionalOnMissingBean public AspectJExpressionPointcutAdvisor aspectJExpressionPointcutAdvisor(PointcutProperites pointcutProperites, CorHandlerInterceptor corHandlerInterceptor){ AspectJExpressionPointcutAdvisor aspectJExpressionPointcutAdvisor = new AspectJExpressionPointcutAdvisor(); aspectJExpressionPointcutAdvisor.setExpression(pointcutProperites.getExpression()); aspectJExpressionPointcutAdvisor.setAdvice(new CorMethodInterceptor(corHandlerInterceptor)); return aspectJExpressionPointcutAdvisor; } 复制代码
6、处理器注入spring @Bean @ConditionalOnMissingBean public CorHandlerInterceptor corHandlerInterceptor(ObjectProvider provider){ MethodInterceptorChain methodInterceptorChain = new MethodInterceptorChain(); loadedHandlerBySpring(provider, methodInterceptorChain); loadedHanlderBySpi(methodInterceptorChain); CorHandlerInterceptor corHandlerInterceptor = new CorHandlerInterceptor(); corHandlerInterceptor.setChain(methodInterceptorChain); return corHandlerInterceptor; } @Bean @ConditionalOnMissingBean public DefaultHandler defaultHandler(){ return new DefaultHandler(); } private void loadedHanlderBySpi(MethodInterceptorChain methodInterceptorChain) { ServiceLoader serviceLoader = ServiceLoader.load(AbstarctHandler.class); Iterator iterator = serviceLoader.iterator(); while(iterator.hasNext()){ AbstarctHandler abstarctHandler = iterator.next(); log.info("load hander by spi -> 【{}】",abstarctHandler.getClass().getName()); methodInterceptorChain.addHandler(abstarctHandler); } } private void loadedHandlerBySpring(ObjectProvider provider, MethodInterceptorChain methodInterceptorChain) { List getListBySpring = provider.getIfAvailable(); if(!CollectionUtils.isEmpty(getListBySpring)){ for (AbstarctHandler abstarctHandler : getListBySpring) { log.info("load hander by spring -> 【{}】",abstarctHandler.getClass().getName()); methodInterceptorChain.addHandler(abstarctHandler); } } } 复制代码示例演示
1、编写业务服务public interface HelloService { String sayHello(String username); } 复制代码@Service public class HelloServiceImpl implements HelloService { @Override public String sayHello(String username) { return "hello : " + username; } } 复制代码
2、编写处理器
一种通过@Component@Component public class HelloServiceNameInterceptor implements AbstarctHandler { @Override public boolean preHandler(Invocation invocation) { Object[] args = invocation.getArgs(); System.out.println("名称校验-->preHandler"); for (Object arg : args) { if("张三".equals(arg)){ return false; } } return true; } @Override public void afterCompletion(Invocation invocation) { System.out.println("名称校验-->afterCompletion:" + Arrays.toString(invocation.getArgs())); } @Override public int getOrder() { return 102; } } 复制代码
一种通过SPIpublic class HelloServiceSpiInterceptor implements AbstarctHandler { @Override public boolean preHandler(Invocation invocation) { Object[] args = invocation.getArgs(); System.out.println("参数转换-->preHandler"); for (int i = 0; i < args.length; i++) { if("lisi".equals(args[i])){ args[i] = "李四"; } } return true; } @Override public void afterCompletion(Invocation invocation) { System.out.println("参数转换-->afterCompletion:" + Arrays.toString(invocation.getArgs())); } @Override public int getOrder() { return -1; } } 复制代码
配置SPI
内容如下com.github.lybgeek.cor.test.interceptor.HelloServiceSpiInterceptor 复制代码
3、配置切点表达式lybgeek: pointcut: expression: execution(* com.github.lybgeek.cor.test.service..*.*(..)) 复制代码
4、测试
观察控制台
发现处理器正常工作总结
所谓的可扩展,指在新增功能时,不需要或者少修改原有的功能。用设计原则来讲就是对修改关闭,对扩展开放。本文的示例如果心细的朋友就会发现,这跟springmvc的拦截器实现是很像的
作者:linyb极客之路
链接:https://juejin.cn/post/7080330791423016990