首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java動態代理實現AOP攔截:從重複代碼到優雅解耦

     編輯:Java 程式設計入門

專案中SOAP服務層調用JNI,每個方法都包含相同邏輯:記錄入口日誌、初始化JavaBean、調用JNI、記錄出口日誌。代碼由Ant自動生成,手工修改維護成本極高。引入動態代理實現AOP攔截,將橫切關注點抽離,實現代碼復用與解耦。

問題代碼示例

public class SOAP {
    private JniInterface jni = new JniClass();
    private Log log = ...;
    
    public JavaBeanA aMethod(JavaBeanA param) {
        log.debug("進入A方法");
        init(param);                    // 重複邏輯1
        JavaBeanA result = jni.aMethod(param);  // 核心業務
        log.debug("退出A方法");           // 重複邏輯2
        return result;
    }
    // 數十個類似方法...
}

AOP攔截器體系設計

1. 核心接口

public interface Interceptor {
    void before(InvokeJniInfo info);        // 方法前
    void after(InvokeJniInfo info);         // 方法後
    void exceptionThrow(InvokeJniInfo info); // 異常時
}

2. 上下文信息載體

public class InvokeJniInfo {
    Object proxy;       // 代理對象
    Method method;      // 被調用方法
    Object[] args;      // 參數列表
    Object result;      // 返回值
    Throwable exception; // 異常信息
    // 構造器、getter/setter...
}

3. 抽象基類

public abstract class AbstractInterceptor implements Interceptor {
    public void before(InvokeJniInfo info) {}
    public void after(InvokeJniInfo info) {}
    public void exceptionThrow(InvokeJniInfo info) {}
}

4. 具體攔截器實現

日誌攔截器

public class LogInterceptor implements Interceptor {
    private Log log = LogFactory.getLog("init");
    
    public void before(InvokeJniInfo info) {
        log.debug("Enter " + info.getMethod().getName());
    }
    public void after(InvokeJniInfo info) {
        log.debug("Exit " + info.getMethod().getName());
    }
    public void exceptionThrow(InvokeJniInfo info) {
        log.error("Error in " + info.getMethod().getName(), info.getException());
    }
}

參數初始化攔截器

public class InitParamsInterceptor extends AbstractInterceptor {
    public void before(InvokeJniInfo info) {
        if (info.getArgs().length > 0) {
            InitContainsObjectNullUtil.initContainsOutParameter(info.getArgs()[0]);
        }
    }
}

動態代理處理器

public class InterceptorHandler implements InvocationHandler {
    private List<Interceptor> interceptors;
    private Object target;
    
    public Object bind(Object obj) {
        this.target = obj;
        return Proxy.newProxyInstance(
            obj.getClass().getClassLoader(),
            obj.getClass().getInterfaces(),
            this
        );
    }
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        InvokeJniInfo info = new InvokeJniInfo(proxy, method, args, null, null);
        
        // 前置攔截
        for (Interceptor ic : getInterceptors()) ic.before(info);
        
        try {
            Object result = method.invoke(target, args);
            info.setResult(result);
            // 後置攔截(逆序)
            for (int i = interceptors.size()-1; i >= 0; i--) 
                interceptors.get(i).after(info);
            return result;
        } catch (Throwable t) {
            info.setException(t);
            // 異常攔截(逆序)
            for (int i = interceptors.size()-1; i >= 0; i--) 
                interceptors.get(i).exceptionThrow(info);
            throw t;
        }
    }
    
    private synchronized List<Interceptor> getInterceptors() {
        if (interceptors == null) {
            interceptors = new ArrayList<>();
            interceptors.add(new LogInterceptor());
            interceptors.add(new InitParamsInterceptor());
            // 可動態擴展其他攔截器
        }
        return interceptors;
    }
}

工廠與使用

public class InterceptorFactory {
    public static Object getInterceptorProxyedObject(String className) {
        InterceptorHandler handler = new InterceptorHandler();
        Object obj = Class.forName(className).newInstance();
        return handler.bind(obj);
    }
}

// 重構後的SOAP類
public class SOAP {
    private JniInterface jni;
    
    public SOAP() {
        jni = (JniInterface) InterceptorFactory.getInterceptorProxyedObject("JniClass");
    }
    
    public JavaBeanA aMethod(JavaBeanA param) {
        return jni.aMethod(param);  // 僅保留核心調用
    }
}

總結

  1. 必須面向接口編程,動態代理要求目標類實現接口
  2. 此即Spring AOP核心原理:代理模式+攔截器鏈+反射調用
  3. Spring要求使用BeanFactory管理Bean,正是為了在創建時植入代理
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved