在nanowar中引入AOP
通过nanocontainer的nanowar和其struts插件完美的实现了IoC模式的透明,但无法在标准的nanowar中引入nanoaop不得不说是一种遗憾。看了一下nanocontainer的代码,决定自己动手给nanowar添加aop的支持。要在组件和实例中支持AOP,首先要引入interceptor chains。可以考虑在XML定义中引入
<aspect interceptor='InterceptorName' pointcuts='Filter'/>标签。这个<aspect>标签与组件或实例的<parameter>标签在同一级别上。其中interceptor指出拦截器的名称。拦截器的实现可以通过标准组件方式在同一个配置文件中进行注册。pointcuts是拦截方法的过滤表达式(perl5的正则表达式,和nanoaop预定义几个过滤规则)。
在nanowar中实现这个<aspect>标签,需要修改ScopedCotainerComposer, XMLContainerBuilder, ContainerRecorder, ServletContainerListener, DefaultLifecycleContainerBuider类。由于拦截器无法在IoC容器初始化的过程中得到实例。因此,还需要引入一个新的通用拦截器类(InterceptorDelegate),作为真正的拦截器实例和需被拦截的组件的调用桥梁。由于对源代码改动量较大,索性就在原来类的前面加上Aspectable前缀引入新的类,但除了AOP部分,其他的保持不变。
ScopedCotainerComposer => AspectableScopedContainerComposer.java
public AspectableScopedContainerComposer() throws ClassNotFoundException {
this(new DynaopAspectablePicoContainerFactory().createContainer());
}
XMLContainerBuilder => AspectableXMLContainerBuilder.java
protected PicoContainer createContainerFromScript(
....
AspectablePicoContainerFactory containerFactory = new DynaopAspectablePicoContainerFactory();
AspectablePicoContainer childContainer = containerFactory
.createContainer(componentAdapterFactory, parentContainer);
cuts = childContainer.getPointcutsFactory();
....
}
private void registerComponentImplementation(NanoContainer container,
Element element) throws ClassNotFoundException,
MalformedURLException {
......
Map interceptors = createInterceptors(element);
......
if (interceptors != null) {
registerComponentInterceptor(container, clazz, interceptors);
}
}
.......
private void registerComponentInterceptor(NanoContainer container,
Class component, String pointcuts, String interceptorKey) {
if (notSet(pointcuts)) {
pointcuts = ALL_METHODS;
}
if (container.getPico() instanceof AspectablePicoContainer) {
AspectablePicoContainer aspectContainer = (AspectablePicoContainer) container
.getPico();
aspectContainer.registerInterceptor(cuts.instancesOf(component),
getMethodPointcut(pointcuts), new InterceptorDelegate(
aspectContainer, interceptorKey));
}
}
.......
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 childElement = (Element) children.item(i);
if (ASPECT.equals(childElement.getNodeName())) {
String interceptor = childElement.getAttribute(INTERCEPTOR);
if (notSet(interceptor))
throw new NanoContainerMarkupException("'" + KEY
+ "' attribute not specified for "
+ element.getNodeName());
String pointcuts = childElement.getAttribute(POINTCUTS);
interceptorMap.put(interceptor, pointcuts);
}
}
}
if (interceptorMap.isEmpty())
return null;
else
return interceptorMap;
}
private MethodPointcut getMethodPointcut(String pointcuts) {
if (OBJECT_METHODS.equals(pointcuts))
return cuts.objectMethods();
if (IS_METHODS.equals(pointcuts))
return cuts.isMethods();
if (ALL_METHODS.equals(pointcuts))
return cuts.allMethods();
if (GET_METHODS.equals(pointcuts))
return cuts.getMethods();
if (SET_METHODS.equals(pointcuts))
return cuts.setMethods();
return cuts.signature(pointcuts);
}
ContainerRecorder => AspectableContainerRecorder.java
public MutablePicoContainer getContainerProxy() {
if (this.container instanceof AspectablePicoContainer)
return (MutablePicoContainer) Proxy.newProxyInstance(getClass().getClassLoader(),
new Class[]{AspectablePicoContainer.class}, invocationRecorder);
else
return (MutablePicoContainer) Proxy.newProxyInstance(getClass().getClassLoader(),
new Class[]{MutablePicoContainer.class}, invocationRecorder);
}
DefaultLifecycleContainerBuider => AspectableLifecycleContainerBuider.java
protected PicoContainer createContainer(PicoContainer parentContainer, Object assemblyScope) {
AspectablePicoContainerFactory containerFactory = new DynaopAspectablePicoContainerFactory();
return containerFactory.createContainer(parentContainer);
}
ServletContainerListener => AspectableServletContainerListener.java
private ContainerBuilder createBuilder(ServletContext context)
throws ClassNotFoundException {
......
if (initParameter.equals(CONTAINER_COMPOSER)) {
ContainerComposer containerComposer =
createContainerComposer(context);
return new AspectableLifecycleContainerBuilder(containerComposer);
}
InterceptorDelegate .java
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.picocontainer.PicoContainer;
import dynaop.Interceptor;
import dynaop.Invocation;
public class InterceptorDelegate implements Interceptor, MethodInterceptor {
private PicoContainer pico;
private Object key;
public InterceptorDelegate(PicoContainer pico, Object key) {
this.pico = pico;
this.key = key;
}
/* (non-Javadoc)
* @see dynaop.Interceptor#intercept(dynaop.Invocation)
*/
public Object intercept(Invocation invocation) throws Throwable {
return ((Interceptor)pico.getComponentInstance(key)).intercept(invocation);
}
/* (non-Javadoc)
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
return ((MethodInterceptor)pico.getComponentInstance(key)).invoke(invocation);
}
}