论坛首页 Java企业应用论坛

关于Spring Aop 覆盖struts2 的Annotation 拦截器

浏览 6888 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-02-19  
当自学struts2的拦截器时,发现跟aop的功能很像,所以想把两个放在一起看看会发生什么。望大哥大姐多多指点哈
第一种情况使用struts2的AbstractInterceptor 拦截器
1. 使用Spring 代理 Struts2 的Action类,advice使用MethodBeforeAdvice
2. 在Action中使用一个继承自AbstractInterceptor的拦截器。
3. 当访问Action时,我认为因为Spring的代理对象在加载时已经被代理,所以它应该运行完Action的Interceptor再执行Spring的advice。结果和我想的一样,首先打印AbstractInterceptorMethodBeforeAdvice的信息,接着再打印MethodBeforeAdvice的内容,最后执行Action。
第二种情况使用struts2的Annotation拦截器
1. Spring 的配置和上面一样
2. 在Action中使用@Before标注一个非execute方法。
3. 当访问Action时,并未像第一种情况那样打印而是只打印了Spring的MethodBeforeAdvice的信息
为什么会这样呢?从陈英华的博文http://chenyinghua.iteye.com/blog/234814中我们了解到其实AbstractInterceptor和MethodBeforeAdvice的底层实现都是依靠的JDK的代理,在他的博文的基础上我加了Annotation,来看看为什么会发生第二种情况。(以下代码大多是借鉴陈英华的博文,在着表示感谢)

步骤1: 定义接口DynamicProxyFactory
package com.interceptor;

public interface DynamicProxyFactory {
	/**
	 * 生成动态代理,并且在调用代理执行函数的时候使用拦截器
	 * 
	 * @param clazz
	 *            需要实现的接口
	 * @param target
	 *            实现此接口的类
	 * @param interceptor
	 *            拦截器
	 * @return
	 */
	public <T> T createProxy(T target, Interceptor interceptor);
}

步骤2: 定义接口Interceptor (本例暂不使用)

package com.interceptor;

import java.lang.reflect.Method;

public interface Interceptor {
	public void before(Method method, Object[] args);

	public void after(Method method, Object[] args);

	public void afterThrowing(Method method, Object[] args, Throwable throwable);

	public void afterFinally(Method method, Object[] args);
}


步骤3: 实现接口DynamicProxyFactory
package com.interceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class DynamicProxyFactoryImpl implements DynamicProxyFactory {
	/**
	 * 生成动态代理,并且在调用代理执行函数的时候使用拦截器
	 * 
	 * @param target
	 *            需要代理的实例
	 * @param interceptor
	 *            拦截器实现,就是我们希望代理类执行函数的前后, 抛出异常,finally的时候去做写什么
	 */

	@SuppressWarnings("unchecked")
	public <T> T createProxy(T target, Interceptor interceptor) {
		// 当前对象的类加载器
		ClassLoader classLoader = target.getClass().getClassLoader();
		// 获取此对象实现的所有接口
		Class<?>[] interfaces = target.getClass().getInterfaces();
		// 利用DynamicProxyInvocationHandler类来实现InvocationHandler
		InvocationHandler handler = new DynamicProxyInvocationHandler(target, interceptor);

		return (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
	}
}


步骤4: 实现调用处理器

package com.interceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 动态代理的调用处理器
 * 
 * @author chen.yinghua
 */
public class DynamicProxyInvocationHandler implements InvocationHandler {
	private Object target;
	private Interceptor interceptor;


	/**
	 * @param target
	 *            需要代理的实例
	 * @param interceptor
	 *            拦截器
	 */
	public DynamicProxyInvocationHandler(Object target, Interceptor interceptor) {
		this.target = target;
		this.interceptor = interceptor;
	}

	/**
	 * @param proxy
	 *            所生成的代理对象
	 * @param method
	 *            调用的方法示例
	 * @args args 参数数组
	 * @Override
	 */
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result = null;
		Method methodBefore=null;
		Class clazz = target.getClass();
		Method methods[] = clazz.getMethods();
		for(Method method0:methods){
			if(method0.isAnnotationPresent(Before.class)){/*取得被Annotation标注的方法*/
				methodBefore = method0;
				System.out.println("method name is "+method0.getName());
			}
		}
		
		if(null != methodBefore){
		 	methodBefore.invoke(this.target);
			result = method.invoke(this.target, args);
		}
		return result;
	}

}

步骤5:声明一个Annotation接口

package com.interceptor;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Target(ElementType.METHOD)  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
public @interface Before { 
	
    
}

所以准备工作做好现在该测试了。

测试
步骤1: 首先,给需要代理的类定义一个接口Service

package com.interceptor;

public interface Service {
	public String greet(String name);
}

步骤2: 实现这个接口,并使用Annotation,编写类ServiceImpl

package com.interceptor;

public class ServiceImpl implements Service {
	
	@Before
	public void sayHello(){
		System.out.print("java say: Hello,");
	}
	public String greet(String name) {
		String result =  name;
		System.out.println(result);
		return result;
	}
}

步骤3: 实现拦截器接口Interceptor,编写类InterceptorImpl(该步骤暂不使用)
步骤4:编写测试类TestDynamicProxy

package com.interceptor;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

import com.opensymphony.xwork2.interceptor.annotations.Before;

public class TestDynamicProxy {
	public TestDynamicProxy() {
		DynamicProxyFactory dynamicProxyFactory = new DynamicProxyFactoryImpl();
		Service service = new ServiceImpl();
		Interceptor interceptor = null;//Interceptor暂不使用
		Service proxy = dynamicProxyFactory.createProxy(service, interceptor);
		proxy.greet(" daniel");
		System.out.println("\n------打印service的Annotation:---------");
		printAnnotation(service);
		System.out.println("\n------打印 proxy 的Annotation:-----------");
		printAnnotation(proxy);
		System.out.println(">>>>>>>>>>>TestDynamicProxy end");
		
	}
	public void printAnnotation(Object object){
		Class interfaces = object.getClass();
		Method[] method = interfaces.getMethods();
		
		Set<Method> set = new HashSet<Method>();
		for (int i = 0; i < method.length; i++) {
			Annotation an[] = method[i].getAnnotations();
			for(Annotation a:an){
				System.out.println("方法 "+method[i].getName()+" 的Annotation标注为 "+a.toString());
			}		
		}
	}
	public static void main(String[] args) {
		new TestDynamicProxy();
	}
}

测试结果为:

method name is sayHello
java say: Hello, daniel

------打印service的Annotation:---------
方法 sayHello 的Annotation标注为 @com.interceptor.Before()

------打印 proxy 的Annotation:-----------
>>>>>>>>>>>TestDynamicProxy end

从结果我们可以看出service经过proxy后Annotation已经不存在了。

打开proxy.java的源码从getProxyClass(ClassLoader loader, Class<?>... interfaces)方法中的
byte[] proxyClassFile =	ProxyGenerator.generateProxyClass(
		    proxyName, interfaces);
		try {
		    proxyClass = defineClass0(loader, proxyName,
			proxyClassFile, 0, proxyClassFile.length);
		} catch (ClassFormatError e) {

代码知道,ProxyGenerator.generateProxyClass方法产生了一个字节数组,反编译ProxyGenerator从一下的两个重要方法
private byte[] generateClassFile()
    {
        addProxyMethod(hashCodeMethod, java/lang/Object);
        addProxyMethod(equalsMethod, java/lang/Object);
        addProxyMethod(toStringMethod, java/lang/Object);
        for(int i = 0; i < interfaces.length; i++)
        {
            Method amethod[] = interfaces[i].getMethods();
            for(int k = 0; k < amethod.length; k++)
                addProxyMethod(amethod[k], interfaces[i]);

        }

        List list;
        for(Iterator iterator = proxyMethods.values().iterator(); iterator.hasNext(); checkReturnTypes(list))
            list = (List)iterator.next();

        try
        {
            methods.add(generateConstructor());
            for(Iterator iterator1 = proxyMethods.values().iterator(); iterator1.hasNext();)
            {
                List list1 = (List)iterator1.next();
                Iterator iterator2 = list1.iterator();
                while(iterator2.hasNext()) 
                {
                    ProxyMethod proxymethod = (ProxyMethod)iterator2.next();
                    fields.add(new FieldInfo(proxymethod.methodFieldName, "Ljava/lang/reflect/Method;", 10));
                    methods.add(proxymethod.generateMethod());
                }
            }

            methods.add(generateStaticInitializer());
        }
        catch(IOException ioexception)
        {
            throw new InternalError("unexpected I/O Exception");
        }
        if(methods.size() > 65535)
            throw new IllegalArgumentException("method limit exceeded");
        if(fields.size() > 65535)
            throw new IllegalArgumentException("field limit exceeded");
        cp.getClass(dotToSlash(className));
        cp.getClass("java/lang/reflect/Proxy");
        for(int j = 0; j < interfaces.length; j++)
            cp.getClass(dotToSlash(interfaces[j].getName()));

        cp.setReadOnly();
        ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
        DataOutputStream dataoutputstream = new DataOutputStream(bytearrayoutputstream);
        try
        {
            dataoutputstream.writeInt(0xcafebabe);
            dataoutputstream.writeShort(0);
            dataoutputstream.writeShort(49);
            cp.write(dataoutputstream);
            dataoutputstream.writeShort(49);
            dataoutputstream.writeShort(cp.getClass(dotToSlash(className)));
            dataoutputstream.writeShort(cp.getClass("java/lang/reflect/Proxy"));
            dataoutputstream.writeShort(interfaces.length);
            for(int l = 0; l < interfaces.length; l++)
                dataoutputstream.writeShort(cp.getClass(dotToSlash(interfaces[l].getName())));

            dataoutputstream.writeShort(fields.size());
            FieldInfo fieldinfo;
            for(Iterator iterator3 = fields.iterator(); iterator3.hasNext(); fieldinfo.write(dataoutputstream))
                fieldinfo = (FieldInfo)iterator3.next();

            dataoutputstream.writeShort(methods.size());
            MethodInfo methodinfo;
            for(Iterator iterator4 = methods.iterator(); iterator4.hasNext(); methodinfo.write(dataoutputstream))
                methodinfo = (MethodInfo)iterator4.next();

            dataoutputstream.writeShort(0);
        }
        catch(IOException ioexception1)
        {
            throw new InternalError("unexpected I/O Exception");
        }
        return bytearrayoutputstream.toByteArray();
    }

    private void addProxyMethod(Method method, Class class1)
    {
        String s;
        Class aclass[];
        Class class2;
        Class aclass1[];
        Object obj;
label0:
        {
            s = method.getName();
            aclass = method.getParameterTypes();
            class2 = method.getReturnType();
            aclass1 = method.getExceptionTypes();
            String s1 = (new StringBuilder()).append(s).append(getParameterDescriptors(aclass)).toString();
            obj = (List)proxyMethods.get(s1);
            if(obj != null)
            {
                Iterator iterator = ((List) (obj)).iterator();
                ProxyMethod proxymethod;
                do
                {
                    if(!iterator.hasNext())
                        break label0;
                    proxymethod = (ProxyMethod)iterator.next();
                } while(class2 != proxymethod.returnType);
                ArrayList arraylist = new ArrayList();
                collectCompatibleTypes(aclass1, proxymethod.exceptionTypes, arraylist);
                collectCompatibleTypes(proxymethod.exceptionTypes, aclass1, arraylist);
                proxymethod.exceptionTypes = new Class[arraylist.size()];
                proxymethod.exceptionTypes = (Class[])arraylist.toArray(proxymethod.exceptionTypes);
                return;
            }
            obj = new ArrayList(3);
            proxyMethods.put(s1, obj);
        }
        ((List) (obj)).add(new ProxyMethod(s, aclass, class2, aclass1, class1));
}

其中并没有发现对Annotation的处理,看来是把Annotation给忽略吧。
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics