DropWizard的AOP扩展点最佳实践

DropWizard的AOP扩展点最佳实践

各类微服务框架都提供了AOP的能力,DW也不例外。AOP特别是在框架层面使用的特别多。使用的原理基本是动态代理模式。

其实我在想,动态代理,最终是运行时,在内存中生成新的类、方法字节码并加载。倘若使用APT将其做成编译期,是否也是可行的。只是一个思考。

可以参考文章:https://blog.csdn.net/sunquan291/article/details/126779400

一、扩展点接口

DW框架提供了对应的扩展点接口,我们只需要实现接口InterceptionService并发布成Bean

@Service
public class FrameInterceptionService implements InterceptionService {

该接口中定义了三个回调接口,分别是

@Contract
public interface InterceptionService {
    /**
     * If the returned filter returns true then the methods
     * of the service will be passed to {@link #getMethodInterceptors(Method)}
     * to determine if a method should be intercepted and the
     * 判断哪些服务的方法和构造函数可以被传入以判断是否要被拦截
     * constructor of the service will be passed to
     * {@link #getConstructorInterceptors(Constructor)} to
     * determine if the constructor should be intercepted
     * 
     * @return The filter that will be applied to a descriptor
     * to determine if it is to be intercepted.  Should not
     * return null
     */
    public Filter getDescriptorFilter();
    
    /**
     * Each non-final method of a service that passes the
     * {@link #getDescriptorFilter} method will be passed
     * to this method to determine if it will intercepted
     * 
     * @param method A non-final method that may
     * be intercepted
     * @return if null (or an empty list) then this method should
     * NOT be intercepted.  Otherwise the list of interceptors to
     * apply to this method
     */
    public List<MethodInterceptor> getMethodInterceptors(Method method);
    
    /**
     * The single chosen constructor of a service that passes the
     * {@link #getDescriptorFilter} method will be passed
     * to this method to determine if it will intercepted
     * 
     * @param constructor A constructor that may
     * be intercepted
     * @return if null (or an empty list) then this constructor should
     * NOT be intercepted.  Otherwise the list of interceptors to
     * apply to this method
     */
    public List<ConstructorInterceptor> getConstructorInterceptors(Constructor<?> constructor);

}

getDescriptorFilter 用于判断哪些服务的方法和构造函数可以被传入以判断是否要被拦截
getMethodInterceptors 普通方法决策使用什么拦截器
getConstructorInterceptors 构造方法决策使用什么拦截器

二、使用示例

本文中FrameInterceptionService,通过判断方法上是否有注解Record,进而决定是否使用MethodInterceptor进行切面处理。

@Service
public class FrameInterceptionService implements InterceptionService {
    private final static MethodInterceptor RECORD_INTERCEPTOR = new RecordInterceptor();

    private final static List<MethodInterceptor> RECORD_LIST = Collections.singletonList(RECORD_INTERCEPTOR);

    public Filter getDescriptorFilter() {
        return BuilderHelper.allFilter();
    }

    public List<MethodInterceptor> getMethodInterceptors(Method method) {
        if (method.isAnnotationPresent(Record.class)) {
            return RECORD_LIST;
        }

        return null;
    }

    public List<ConstructorInterceptor> getConstructorInterceptors(
            Constructor<?> constructor) {

        return null;
    }
}

方法拦截器功能实现,针对方向执行进行相关调用明细的记录,方便后序调用数据分析。

public class RecordInterceptor implements MethodInterceptor {
	@Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Method m = invocation.getMethod();
        String className = m.getDeclaringClass().getName();
        String methodName = m.getName();

        Object retVal;
        if(TestFrame.enableToRecord(className,methodName)){
            retVal = onRecordInvovation(invocation, className, methodName);
        }else if(TestFrame.isTestEnvironment()){
            retVal = onMockInvovation(invocation, className, methodName);
        }else {
            retVal = invocation.proceed();
        }
        return retVal;
    }

    private Object onMockInvovation(MethodInvocation invocation, String className, String methodName) throws Throwable {
        Object retVal;
        Object args[] = invocation.getArguments();
        if(TestFrame.isMock(className,methodName)){
            retVal = TestFrame.mockReturnValueAndDelete(className,methodName);
        }else{
            retVal = invocation.proceed();
        }

        return retVal;
    }

    private RecordItem createRecordItem(String className,String methodName,Throwable throwable,Object retVal,Object[] args){
        if(throwable==null){
            return RecordItem.createRecordItem(className, methodName,retVal,args);
        }else {
            return RecordItem.createRecordItem(className, methodName,throwable,args);
        }
    }

    private Object onRecordInvovation(MethodInvocation invocation, String className, String methodName) throws Throwable {
        Object retVal = null;
        Object args[] = invocation.getArguments();

        Throwable throwable = null;
        try {
            retVal = invocation.proceed();
        }catch (Throwable t){
            throwable = t;
        }

        RecordItem item = createRecordItem(className, methodName,throwable,retVal,args);

        TestFrame.addRecordItem(item);

        if(TestFrame.isRecordStartLocation(className,methodName)){
            TestFrame.saveRecordResult();
            TestFrame.endRecord();
        }

        if(throwable!=null){
           throw  throwable;
        }

        return retVal;
    }
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值