读书人

注脚+动态代理的一个例子

发布时间: 2012-08-24 10:00:21 作者: rapoo

注解+动态代理的一个例子

在公司没事干了,学习下动态代理模式(关于代理的基础只是有很多帖子都有我就不重复了),做了个注解动态代理的例子,给那些学习注解或动态代理的初学者。

花了将近1小时,没做个什么优化,大牛勿喷。

几个主要的类:

注解类:

package test2;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)public @interface ProxyTag {public Class proxyClass();}
?

代理类父类:

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public abstract class  ProxyBean implements InvocationHandler{private Object o;private String methodName;public Object bind(Object obj,String methodName){this.o = obj;return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);}public Object invoke(Object proxy, Method method, Object[] obj)throws Throwable {if(method.getName().equals(methodName)){this.before();Object result = method.invoke(o, obj);this.after();return result;}else{Object result = method.invoke(o, obj);return result;}}public abstract void before();public abstract void after();}

代理工厂:

import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class ProxyFactory {public static <T> T getProxyBean(Class<T> clazz){T t = (T) newInstance(clazz);Method[] methods = clazz.getMethods();for(int i=0;i<methods.length;i++){ProxyTag pt = methods[i].getAnnotation(ProxyTag.class);if(pt == null){continue;}ProxyBean pb = (ProxyBean) newInstance(pt.proxyClass());t = (T) pb.bind(t, methods[i].getName());}return t;}private static Object newInstance(final Class clazz){try {Constructor cons = clazz.getConstructor();return cons.newInstance(new Class[]{});} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (NoSuchMethodException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}}

?测试类:

?

package test2;public class ProxyClass extends ProxyBean{public void after() {System.out.println("after....");}public void before() {System.out.println("before....");}}

?

public class ProxyClass2 extends ProxyBean{public void after() {System.out.println("after2....");}public void before() {System.out.println("before2....");}}
?
public interface IDemo {public void sayHello();public void sayHello2();}
?
public class Demo implements IDemo{@ProxyTag(proxyClass=ProxyClass.class)public void sayHello(){System.out.println("hello....");}@ProxyTag(proxyClass=ProxyClass2.class)public void sayHello2(){System.out.println("hello2....");}}
public class Test {/** * @param args */public static void main(String[] args) {IDemo demo = ProxyFactory.getProxyBean(Demo.class);demo.sayHello();System.out.println("-----------------------------");demo.sayHello2();}}
before....hello....after....-----------------------------before2....hello2....after2....
我没有看过spring的拦截器源码,不过实现原理上估计差不多,需要源码请下载附件
刚刚发现代码有点笔误的地方,容易让人误解,展示的代码已经修改过来了,附件里的代码请自己对照着修改一下
1 楼 dwbin 2011-03-15 不错,把异常再抛出来,ProxyBean里面的before和after可以设计成接口注入到某个容器里面,再有一个applicationcontext的概念我觉得就蛮好了 2 楼 t42dw 2011-03-15 <p><span>
<div class="quote_div">我不明白为啥demo可以使用两次,也就是调用两次方法?准确的说就是为啥两次调用可以区分是用那个ProxyClass?</div>
</span></p>
<p><span>demo.sayHello(); ??</span></p>
<p><span>????????System.out.println(</span><span class="string">"-----------------------------"</span><span>); ??</span></p>
<p><span>????????demo.sayHello2();???</span></p>
<p>?</p>
<p><span>难道是句代码可以注册多个代理?</span></p>
<p><span>t = (T) pb.bind(t, pb, methods[i].getName());<br></span></p>
<p>?</p>
<p>?</p>
<p>?</p> 3 楼 Cindy_Lee 2011-03-15 <div class="quote_title">t42dw 写道</div>
<div class="quote_div">
<p><span>
</span></p>
<div class="quote_div">我不明白为啥demo可以使用两次,也就是调用两次方法?准确的说就是为啥两次调用可以区分是用那个ProxyClass?</div>
<p>?</p>
<p><span>demo.sayHello(); ??</span></p>
<p><span>????????System.out.println(</span><span class="string">"-----------------------------"</span><span>); ??</span></p>
<p><span>????????demo.sayHello2();???</span></p>
<p>?</p>
<p><span>难道是句代码可以注册多个代理?</span></p>
<p><span>t = (T) pb.bind(t, pb, methods[i].getName());<br></span></p>
<p>?</p>
<p>?</p>
<p>?</p>
</div>
<p>请认真看invoke方法</p> 4 楼 t42dw 2011-03-16 <div class="quote_title">Cindy_Lee 写道</div>
<div class="quote_div">
<div class="quote_title">t42dw 写道</div>
<div class="quote_div">
<p>?</p>
<div class="quote_div">我不明白为啥demo可以使用两次,也就是调用两次方法?准确的说就是为啥两次调用可以区分是用那个ProxyClass?</div>
<p>?</p>
<p><span>demo.sayHello(); ??</span></p>
<p><span>????????System.out.println(</span><span class="string">"-----------------------------"</span><span>); ??</span></p>
<p><span>????????demo.sayHello2();???</span></p>
<p>?</p>
<p><span>难道是句代码可以注册多个代理?</span></p>
<p><span>t = (T) pb.bind(t, pb, methods[i].getName());<br></span></p>
<p>?</p>
<p>?</p>
<p>?</p>
</div>
<p>请认真看invoke方法</p>
</div>
<p>?</p>
<p>哦,有递归...</p> 5 楼 liuyes 2011-03-16 相当不错,注释很强大 6 楼 jeho0815 2011-03-16 ProxyTag pt = methods[i].getAnnotation(ProxyTag.class); 这句话有问题啊。。。 7 楼 Cindy_Lee 2011-03-16 jeho0815 写道ProxyTag pt = methods[i].getAnnotation(ProxyTag.class); 这句话有问题啊。。。
啥问题 望指教 8 楼 baiweiyll 2011-03-17
用这种吧 Method[] methods = clazz.getDeclaredMethods();
少循环几次 9 楼 Cindy_Lee 2011-03-17 baiweiyll 写道
用这种吧 Method[] methods = clazz.getDeclaredMethods();
少循环几次
呵呵很有道理,是我疏忽了 10 楼 ucfjepl 2011-03-19 liuyes 写道相当不错,注释很强大
的确非常强大.....

读书人网 >软件架构设计

热点推荐