AOP模拟第三方接口调用返回

应用系统开发时,与第三方系统对接是常见的需求,当我们兴冲冲按照接口文档开发好代码的时候,第三方系统却未准备好,而我们编写的业务代码散落与业务模块的各个地方。为了不影响我们系统的运行,必须暂时屏蔽这部分代码调用。
怎么办?

  1. 方法一: 注释掉这些代码不就行了吗,确实,大部分情况下我们可能就是这样做的。

  2. 方法二: 配置开关项,接口未准备好的时候设为0或false,启用时设置为1或true,这好像是我们能想到的比方法一更好的方法,不过针对调用前频繁的 if 判断和对代码结构的整体破坏让人十分不爽。

    有没有办法摆脱方法二的弊端呢!答案是肯定的,祭出我们的spring AOP。
    假定我们的接口返回对象为InvokeResult,全部的接口方法均封装好放在包com.fly.demo.api下面。

/**
* 
* 接口返回对象
* 
* @author 00fly
* @version [版本号, 2018年12月10日]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class InvokeResult
{
 private Object data;
 
 private boolean success = false;
 
 private String errorMessage;
 
 public Object getData()
 {
     return data;
 }
 
 public void setData(Object data)
 {
     this.data = data;
 }
 
 public boolean isSuccess()
 {
     return success;
 }
 
 public void setSuccess(boolean success)
 {
     this.success = success;
 }
 
 public String getErrorMessage()
 {
     return errorMessage;
 }
 
 public void setErrorMessage(String errorMessage)
 {
     this.errorMessage = errorMessage;
 }
}

aop核心代码


import java.lang.reflect.Method;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.RequestMapping;

import com.fly.core.entity.InvokeResult;

/**
 * aop 处理接口未启用返回的接口调用结果
 *
 * @author 00fly
 * @version [版本号, 2018年12月10日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Aspect
@Component
public class MockCalledAspect
{
    static final Logger LOGGER = LoggerFactory.getLogger(MockCalledAspect.class);
    
    /**
     * 配置文件配置接口是否启用
     */
    @Value("${interface.enable:false}")
    private boolean enable;
    
    /**
     * 接口是否启用
     */
    public boolean isEnable()
    {
        return enable;
    }
    
    @Around("within(com.fly.demo.api.*Interface)")
    public Object around(ProceedingJoinPoint joinPoint)
        throws Throwable
    {
        String className = joinPoint.getTarget().getClass().getName();
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = new StringBuffer(className).append(".").append(method.getName()).toString();
        boolean isController = method.isAnnotationPresent(RequestMapping.class);
        Object result = null;
        StopWatch clock = new StopWatch();
        clock.start(methodName);
        
        // 接口未启用的话,构造返回失败信息
        if (className.startsWith("com.fly.demo.api") && !isEnable())
        {
            String returnClassName = method.getReturnType().getSimpleName();
            if ("InvokeResult".equals(returnClassName))
            {
                InvokeResult stringInvokeResult = new InvokeResult();
                stringInvokeResult.setSuccess(false);
                stringInvokeResult.setErrorMessage("接口配置未启用");
                result = stringInvokeResult;
            }
            if (result != null)
            {
                LOGGER.info("执行{} 返回结果:{}", methodName, ToStringBuilder.reflectionToString(result));
            }
            if (result == null)
            {
                result = joinPoint.proceed();
            }
        }
        clock.stop();
        if (isController)
        {
            LOGGER.info("end in {} ms, method = {}\n", clock.getTotalTimeMillis(), clock.getLastTaskName());
        }
        else
        {
            LOGGER.info("running {} ms, method = {}", clock.getTotalTimeMillis(), clock.getLastTaskName());
        }
        return result;
    }
}

我们的模块接口代码什么都不用动,就实现了模拟接口的返回是不是很棒!

而接口启用时我们可以删除上面这段代码或者isEnable返回值设置为true或者在配置文件将interface.enable设为true。

—over—

你可能感兴趣的:(java,spring)