NanoContainer 的 NanoWar 與 Struts 插件完美實現了 IoC 透明化,但標準版缺乏 AOP 支援。本文記錄透過修改核心類、引入攔截器鏈與委派模式,為 NanoWar 增加 AOP 能力的完整實作過程。
| 原類別 | 新類別(Aspectable 前綴) | 關鍵變更 |
| ScopedContainerComposer | AspectableScopedContainerComposer | 建構子使用 DynaopAspectablePicoContainerFactory |
| XMLContainerBuilder | AspectableXMLContainerBuilder | 解析 <aspect>、註冊攔截器、getMethodPointcut 解析 pointcut |
| ContainerRecorder | AspectableContainerRecorder | getContainerProxy() 返回 AspectablePicoContainer 代理 |
| DefaultLifecycleContainerBuilder | AspectableLifecycleContainerBuilder | createContainer() 返回 AOP 容器 |
| ServletContainerListener | AspectableServletContainerListener | createBuilder() 返回 AspectableLifecycleContainerBuilder |
關鍵代碼片段
XMLContainerBuilder 解析 aspect
private Map createInterceptors(Element element) {
Map interceptorMap = new HashMap();
NodeList children = element.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
if (children.item(i) instanceof Element) {
Element child = (Element) children.item(i);
if ("aspect".equals(child.getNodeName())) {
String interceptor = child.getAttribute("interceptor");
String pointcuts = child.getAttribute("pointcuts");
interceptorMap.put(interceptor, pointcuts);
}
}
}
return interceptorMap.isEmpty() ? null : interceptorMap;
}
註冊攔截器
private void registerComponentInterceptor(NanoContainer container, Class component, String pointcuts, String interceptorKey) {
if (pointcuts == null) pointcuts = "all-methods";
if (container.getPico() instanceof AspectablePicoContainer) {
AspectablePicoContainer aspectContainer = (AspectablePicoContainer) container.getPico();
aspectContainer.registerInterceptor(
cuts.instancesOf(component),
getMethodPointcut(pointcuts),
new InterceptorDelegate(aspectContainer, interceptorKey)
);
}
}
InterceptorDelegate 橋樑實現
public class InterceptorDelegate implements dynaop.Interceptor, org.aopalliance.intercept.MethodInterceptor {
private PicoContainer pico;
private Object key;
public InterceptorDelegate(PicoContainer pico, Object key) {
this.pico = pico; this.key = key;
}
public Object intercept(dynaop.Invocation invocation) throws Throwable {
return ((dynaop.Interceptor) pico.getComponentInstance(key)).intercept(invocation);
}
public Object invoke(org.aopalliance.intercept.MethodInvocation invocation) throws Throwable {
return ((org.aopalliance.intercept.MethodInterceptor) pico.getComponentInstance(key)).invoke(invocation);
}
}
XML 配置範例
<component class="com.example.ServiceImpl">
<aspect interceptor="loggingInterceptor" pointcuts="public * *(..)"/>
<aspect interceptor="txInterceptor" pointcuts="* save*(..), * delete*(..)"/>
</component>
實作心得
- 修改量較大,採用
Aspectable 前綴新建類別,保持原有邏輯不變,降低風險。
InterceptorDelegate 同時實現 dynaop.Interceptor 與 MethodInterceptor,相容 NanoAOP 與 AOP Alliance 兩種 API。
- Pointcut 解析支援預定義關鍵字(
all-methods、get-methods 等)與自訂正則。
- 上一篇文章: JPF Controller 中使用 Request 傳遞數據到 JSP 頁面
- 下一篇文章: JieFormattedDateBox:Swing 格式化日期時間輸入元件完整原始碼解析
Copyright ©
程式碼之家 All Rights Reserved