论坛首页 Java企业应用论坛

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

浏览 14119 次
精华帖 (1) :: 良好帖 (0) :: 新手帖 (6) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-03-14   最后修改:2011-03-16

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

花了将近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 block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.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的拦截器源码,不过实现原理上估计差不多,需要源码请下载附件
刚刚发现代码有点笔误的地方,容易让人误解,展示的代码已经修改过来了,附件里的代码请自己对照着修改一下
   发表时间:2011-03-15  
不错,把异常再抛出来,ProxyBean里面的before和after可以设计成接口注入到某个容器里面,再有一个applicationcontext的概念我觉得就蛮好了
0 请登录后投票
   发表时间:2011-03-15  

我不明白为啥demo可以使用两次,也就是调用两次方法?准确的说就是为啥两次调用可以区分是用那个ProxyClass 

demo.sayHello();   

        System.out.println("-----------------------------");   

        demo.sayHello2();   

 

难道是句代码可以注册多个代理?

t = (T) pb.bind(t, pb, methods[i].getName());

 

 

 

0 请登录后投票
   发表时间:2011-03-15  
t42dw 写道

我不明白为啥demo可以使用两次,也就是调用两次方法?准确的说就是为啥两次调用可以区分是用那个ProxyClass 

 

demo.sayHello();   

        System.out.println("-----------------------------");   

        demo.sayHello2();   

 

难道是句代码可以注册多个代理?

t = (T) pb.bind(t, pb, methods[i].getName());

 

 

 

请认真看invoke方法

0 请登录后投票
   发表时间:2011-03-16  
Cindy_Lee 写道
t42dw 写道

 

我不明白为啥demo可以使用两次,也就是调用两次方法?准确的说就是为啥两次调用可以区分是用那个ProxyClass 

 

demo.sayHello();   

        System.out.println("-----------------------------");   

        demo.sayHello2();   

 

难道是句代码可以注册多个代理?

t = (T) pb.bind(t, pb, methods[i].getName());

 

 

 

请认真看invoke方法

 

哦,有递归...

0 请登录后投票
   发表时间:2011-03-16  
相当不错,注释很强大
0 请登录后投票
   发表时间:2011-03-16  
ProxyTag pt = methods[i].getAnnotation(ProxyTag.class); 这句话有问题啊。。。
0 请登录后投票
   发表时间:2011-03-16  
jeho0815 写道
ProxyTag pt = methods[i].getAnnotation(ProxyTag.class); 这句话有问题啊。。。

啥问题 望指教
0 请登录后投票
   发表时间:2011-03-17  
      
    用这种吧 Method[] methods = clazz.getDeclaredMethods();
    少循环几次
0 请登录后投票
   发表时间:2011-03-17  
baiweiyll 写道
      
    用这种吧 Method[] methods = clazz.getDeclaredMethods();
    少循环几次

呵呵很有道理,是我疏忽了
0 请登录后投票
论坛首页 Java企业应用版

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