当自学struts2的拦截器时,发现跟aop的功能很像,所以想把两个放在一起看看会发生什么。望大哥大姐多多指点哈
[b]第一种情况使用struts2的AbstractInterceptor 拦截器[/b]
1. 使用Spring 代理 Struts2 的Action类,advice使用MethodBeforeAdvice
2. 在Action中使用一个继承自AbstractInterceptor的拦截器。
3. 当访问Action时,我认为因为Spring的代理对象在加载时已经被代理,所以它应该运行完Action的Interceptor再执行Spring的advice。结果和我想的一样,首先打印AbstractInterceptorMethodBeforeAdvice的信息,接着再打印MethodBeforeAdvice的内容,最后执行Action。
[b]第二种情况使用struts2的Annotation拦截器[/b]
1. Spring 的配置和上面一样
2. 在Action中使用@Before标注一个非execute方法。
3. 当访问Action时,并未像第一种情况那样打印而是只打印了Spring的MethodBeforeAdvice的信息
为什么会这样呢?从陈英华的博文[url]http://chenyinghua.iteye.com/blog/234814[/url]中我们了解到其实AbstractInterceptor和MethodBeforeAdvice的底层实现都是依靠的JDK的代理,在他的博文的基础上我加了Annotation,来看看为什么会发生第二种情况。(以下代码大多是借鉴陈英华的博文,在着表示感谢)
步骤1: 定义接口[b]DynamicProxyFactory[/b]
步骤2: 定义接口[b]Interceptor[/b] (本例暂不使用)
步骤3: 实现[b]接口DynamicProxyFactory [/b]
步骤4: 实现调用[b]处理器[/b]
步骤5:声明一个[b]Annotation[/b]接口
所以准备工作做好现在该测试了。
[b]测试[/b]
步骤1: 首先,给需要代理的类定义一个接口[b]Service [/b]
步骤2: 实现这个接口,并使用Annotation,编写类[b]ServiceImpl [/b]
步骤3: 实现拦截器接口Interceptor,编写类InterceptorImpl(该步骤暂不使用)
步骤4:编写测试类[b]TestDynamicProxy[/b]
[b]测试结果为:
[/b]
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)方法中的
代码知道,ProxyGenerator.generateProxyClass方法产生了一个字节数组,反编译ProxyGenerator从一下的两个重要方法
其中并没有发现对Annotation的处理,看来是把Annotation给忽略吧。
[b]第一种情况使用struts2的AbstractInterceptor 拦截器[/b]
1. 使用Spring 代理 Struts2 的Action类,advice使用MethodBeforeAdvice
2. 在Action中使用一个继承自AbstractInterceptor的拦截器。
3. 当访问Action时,我认为因为Spring的代理对象在加载时已经被代理,所以它应该运行完Action的Interceptor再执行Spring的advice。结果和我想的一样,首先打印AbstractInterceptorMethodBeforeAdvice的信息,接着再打印MethodBeforeAdvice的内容,最后执行Action。
[b]第二种情况使用struts2的Annotation拦截器[/b]
1. Spring 的配置和上面一样
2. 在Action中使用@Before标注一个非execute方法。
3. 当访问Action时,并未像第一种情况那样打印而是只打印了Spring的MethodBeforeAdvice的信息
为什么会这样呢?从陈英华的博文[url]http://chenyinghua.iteye.com/blog/234814[/url]中我们了解到其实AbstractInterceptor和MethodBeforeAdvice的底层实现都是依靠的JDK的代理,在他的博文的基础上我加了Annotation,来看看为什么会发生第二种情况。(以下代码大多是借鉴陈英华的博文,在着表示感谢)
步骤1: 定义接口[b]DynamicProxyFactory[/b]
package com.interceptor;
public interface DynamicProxyFactory {
/**
* 生成动态代理,并且在调用代理执行函数的时候使用拦截器
*
* @param clazz
* 需要实现的接口
* @param target
* 实现此接口的类
* @param interceptor
* 拦截器
* @return
*/
public <T> T createProxy(T target, Interceptor interceptor);
}
步骤2: 定义接口[b]Interceptor[/b] (本例暂不使用)
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: 实现[b]接口DynamicProxyFactory [/b]
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: 实现调用[b]处理器[/b]
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:声明一个[b]Annotation[/b]接口
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 {
}
所以准备工作做好现在该测试了。
[b]测试[/b]
步骤1: 首先,给需要代理的类定义一个接口[b]Service [/b]
package com.interceptor;
public interface Service {
public String greet(String name);
}
步骤2: 实现这个接口,并使用Annotation,编写类[b]ServiceImpl [/b]
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:编写测试类[b]TestDynamicProxy[/b]
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();
}
}
[b]测试结果为:
[/b]
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给忽略吧。