A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 佟亚鹏 中级黑马   /  2012-9-5 10:44  /  2995 人查看  /  17 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 佟亚鹏 于 2012-9-6 08:25 编辑

我正在自己写一个像sping这样的框架,现在实现了注入,但是aop的实现,只能代理接口,并且代理接口里的所有方法,sping里面既可以代理接口也可以代理类,并且可以代理到一个具体的方法上面,写到这个地方卡壳了,大家能给点思路吗,我使用的是java对动态代理的支持,貌似只支持代理接口。我把项目打包上传,大家可以看看,给点意见,里面还有一个简单的数据库连接池的实现

MyFramework.zip

54.42 KB, 下载次数: 234

自己写的小框架

17 个回复

倒序浏览
没有人吗,自己先顶下。。。。。{:soso_e135:}
回复 使用道具 举报
用JDK的动态代理的东西的话,需要记住三个要点:
1 定义自己的接口.例如IPrint接口,该接口有一个print()方法.
2 定义一个实现接口的类,例如IPrintImpl类,该类要有print()方法的具体实现.
3 最后用Proxy.newInstance()方法生成一个实例,如果要调用print()方法,那么这个实例不能转型为IPrintImp类型,只能转型为IPrint类型,才能调用print()方法.

评分

参与人数 1技术分 +1 收起 理由
滔哥 + 1

查看全部评分

回复 使用道具 举报
马镱洵 发表于 2012-9-5 14:05
用JDK的动态代理的东西的话,需要记住三个要点:
1 定义自己的接口.例如IPrint接口,该接口有一个print()方法. ...

我想实现即可以代理类也可以代理接口,还有不止把接口里的所有方法都代理,还可以代理到具体的一个方法,
回复 使用道具 举报
佟亚鹏 发表于 2012-9-5 14:25
我想实现即可以代理类也可以代理接口,还有不止把接口里的所有方法都代理,还可以代理到具体的一个方法, ...

两种解决方案:
1 那就自己写一个代理类,不借助JDK的动态代理功能.
2 另外定义一个接口,比如IPrint2接口,在该接口里定义你想要的方法,再将你的实例类又实现这个新定义的接口,用Proxy.newInstance()方法生成一个实例,将这个生成的实例转型为IPrint2类型,这样就可以了.
回复 使用道具 举报
马镱洵 发表于 2012-9-5 14:35
两种解决方案:
1 那就自己写一个代理类,不借助JDK的动态代理功能.
2 另外定义一个接口,比如IPrint2接口, ...

自己写代理程序非常麻烦,需要拼java代码,还需要动态编译,目前就使用第二种方案吧,另外代理到具体某个方法我自己在琢磨琢磨,谢谢你的回答
回复 使用道具 举报
佟亚鹏 发表于 2012-9-5 18:32
自己写代理程序非常麻烦,需要拼java代码,还需要动态编译,目前就使用第二种方案吧,另外代理到具体某个 ...


不客气,第二种方案确实是最好的方案.
  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. import java.lang.reflect.Proxy;

  4. class MyDynamicProxy implements InvocationHandler {
  5.         private Object implementationer;

  6.         // public MyDynamicProxy(Object Implementationer) {
  7.         // this.Implementationer = Implementationer;
  8.         // }

  9.         public Object getImplementationer() {
  10.                 return implementationer;
  11.         }

  12.         public void setImplementationer(Object implementationer) {
  13.                 this.implementationer = implementationer;
  14.         }

  15.         public Object creatTrueRole(Object object) {
  16.                 this.implementationer = object;
  17.                 return Proxy.newProxyInstance(implementationer.getClass()
  18.                                 .getClassLoader(), object.getClass().getInterfaces(), this);
  19.         }

  20.         @Override
  21.         public Object invoke(Object proxy, Method method, Object[] args)
  22.                         throws Throwable {
  23.                 Object o = null;
  24.                 o = method.invoke(this.implementationer, args);

  25.                 // proxy只是接口的实例,不是接口实现类的实例.
  26.                 // System.out.println("proxy: " + (proxy instanceof IPrint2));

  27.                 return o;
  28.         }
  29. }
复制代码
implementationer就是你的真正的实现接口的类的对象,在外部调用creatTrueRole()方法时,要传入一个实现了你自己定义的接口的一个实例进去,返回的结果就是动态代理机制所代理的对象,不过要想直接使用这个代理对象,要先把这个返回的代理对象转型为相应的接口,再通过接口的引用来调用已实现的方法.

  1. public class DynamicProxyTest {
  2.         public static void main(String[] args) {
  3.                 IPrint mo = (IPrint) new MyDynamicProxy().creatTrueRole(new MyOne());
  4.                 IPrint2 mo2 = (IPrint2) new MyDynamicProxy().creatTrueRole(new MyOne());

  5.                 // 以下注释掉的代码是错误代码,不能将用动态代理生成的对象转型为实现接口的类的类型.
  6.                 // MyOne mo = (MyOne) new MyDynamicProxy().creatTrueRole(new MyOne());
  7.                 // MyOne mo2 = (MyOne) new MyDynamicProxy().creatTrueRole(new MyOne());

  8.                 mo.print();
  9.                 mo.print2();
  10.                 mo.print3();
  11.                 mo2.print4();
  12.                 mo2.print5();
  13.                 mo2.print6();
  14.         }
  15. }

  16. class MyOne implements IPrint, IPrint2 {
  17.         @Override
  18.         public void print() {
  19.                 System.out.println("print");
  20.         }

  21.         @Override
  22.         public void print2() {
  23.                 System.out.println("print2");
  24.         }

  25.         @Override
  26.         public void print3() {
  27.                 System.out.println("print3");
  28.         }

  29.         @Override
  30.         public void print4() {
  31.                 System.out.println("print4");
  32.         }

  33.         @Override
  34.         public void print5() {
  35.                 System.out.println("print5");
  36.         }

  37.         @Override
  38.         public void print6() {
  39.                 System.out.println("print6");
  40.         }
  41. }

  42. interface IPrint {
  43.         // @MyAnnotation(b = "two")
  44.         void print();

  45.         void print2();

  46.         // @MyAnnotation(b = "bb")
  47.         void print3();
  48. }

  49. interface IPrint2 {
  50.         void print4();

  51.         void print5();

  52.         void print6();
  53. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
王德升 + 1 赞一个!

查看全部评分

回复 使用道具 举报
马镱洵 发表于 2012-9-5 19:43
不客气,第二种方案确实是最好的方案.implementationer就是你的真正的实现接口的类的对象,在外部调用creat ...

这个是我写的模仿sping的用jdk代理api生成代理的代码,可以在方法前后都加入逻辑,以及异常处理
有一个接口advice,里面包括四个方法,实现的功能看方法名
public interface Advice {
        void before(Object proxy, Method method, Object[] args);
        void after(Object proxy, Method method, Object[] args);
        void exception(Object proxy, Method method, Object[] args);
        void beforeAndAfter(Object proxy, Method method, Object[] args);       
}

还有一个代理类生成工厂
public class ProxyFactory {
       
        private Object target;
        private Advice advice;
       
        public Object createProxy() {
                Object proxyObj = Proxy.newProxyInstance(
                                target.getClass().getClassLoader(),
                                target.getClass().getInterfaces(),
                                new InvocationHandler(){       
                                        @Override
                                        public Object invoke(Object proxy, Method method, Object[] args)
                                                        throws Throwable {                                                       
                                                Object result = null;
                                                try {
                                                        advice.beforeAndAfter(proxy, method, args);
                                                        advice.before(proxy, method, args);                                                       
                                                        result = method.invoke(target, args);
                                                        advice.after(proxy, method, args);
                                                        advice.beforeAndAfter(proxy, method, args);
                                                } catch (Exception e) {
                                                         advice.exception(proxy, method, args);
                                                }
                                                return result;                                               
                                        }
                                });       

                return proxyObj;
        }
        public Object getProxy(Object target,Advice advice) {
                this.target = target;
                this.advice = advice;
                return getProxy();
        }
        public Object getTarget() {
                return target;
        }
        public void setTarget(Object target) {
                this.target = target;
        }
        public Advice getAdvice() {
                return advice;
        }
        public void setAdvice(Advice advice) {
                this.advice = advice;
        }
}
这样做了一层封装,使接口更加好用了,有时间咱俩讨论下自己写代理类,这样不用再局限于Java提供的支持了。。

评分

参与人数 1技术分 +1 收起 理由
王德升 + 1 赞一个!

查看全部评分

回复 使用道具 举报
  1. public Object getProxy(Object target,Advice advice) {
  2.                 this.target = target;
  3.                 this.advice = advice;
  4.                 return getProxy();
  5.         }
复制代码
你这个方法是不是写错了,再说你这个方法是多余的(这个方法和setAdvice()方法与setTarget()方法重复了),你的这种方案,确实可以达到"在同一个接口里除了可以实现必须要实现的方法之外,还可以在实现必须要实现方法之前与之后做一些其他的事情"的目的.不过你只要在调用createProxy()方法之前,必须要先给ProxyFactory类的target成员与advice成员同时赋上一个实现了Advice接口的类的对象,然后在外部调用createProxy()方法,返回的结果就是实际的代理对象,但是如果要真正成功调用到接口里的方法,必须要将这个所返回的代理对象转型成为Advice接口才可以.以下见具体代码:
  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. import java.lang.reflect.Proxy;

  4. interface Advice {

  5.         void before(Object proxy, Method method, Object[] args);

  6.         void after(Object proxy, Method method, Object[] args);

  7.         void exception(Object proxy, Method method, Object[] args);

  8.         void beforeAndAfter(Object proxy, Method method, Object[] args);

  9.         /**
  10.          * 真正必须要实现的方法
  11.          */
  12.         void print();

  13. }

  14. class AdviceImpl implements Advice {

  15.         @Override
  16.         public void before(Object proxy, Method method, Object[] args) {
  17.                 System.out.println("before");
  18.         }

  19.         @Override
  20.         public void after(Object proxy, Method method, Object[] args) {
  21.                 System.out.println("after");
  22.         }

  23.         @Override
  24.         public void exception(Object proxy, Method method, Object[] args) {
  25.                 System.out.println("exception");
  26.         }

  27.         @Override
  28.         public void beforeAndAfter(Object proxy, Method method, Object[] args) {
  29.                 System.out.println("beforeAndAfter");
  30.         }

  31.         @Override
  32.         public void print() {
  33.                 System.out.println("真正想要实现的方法: print()");
  34.         }

  35. }

  36. // 还有一个代理类生成工厂
  37. class ProxyFactory {

  38.         private Object target;
  39.         private Advice advice;

  40.         public Object createProxy() {
  41.                 AdviceImpl adviceImpl = new AdviceImpl();
  42.                 getProxy(adviceImpl, adviceImpl);
  43.                 Object proxyObj = Proxy.newProxyInstance(target.getClass()
  44.                                 .getClassLoader(), target.getClass().getInterfaces(),
  45.                                 new InvocationHandler() {
  46.                                         @Override
  47.                                         public Object invoke(Object proxy, Method method,
  48.                                                         Object[] args) throws Throwable {
  49.                                                 Object result = null;
  50.                                                 try {
  51.                                                         advice.beforeAndAfter(proxy, method, args);
  52.                                                         advice.before(proxy, method, args);
  53.                                                         result = method.invoke(target, args);
  54.                                                         advice.after(proxy, method, args);
  55.                                                         advice.beforeAndAfter(proxy, method, args);
  56.                                                 } catch (Exception e) {
  57.                                                         advice.exception(proxy, method, args);
  58.                                                 }
  59.                                                 return result;
  60.                                         }
  61.                                 });
  62.                 return proxyObj;
  63.         }

  64.         /**
  65.          * 这个方法我给你改一下,就不需要后面的几个方法了.
  66.          *
  67.          * @param target
  68.          * @param advice
  69.          * @return
  70.          */
  71.         public void getProxy(Object target, Advice advice) {
  72.                 this.target = target;
  73.                 this.advice = advice;
  74.                 // return getProxy(this.target, this.advice);
  75.         }

  76.         // public Object getTarget() {
  77.         // return target;
  78.         // }
  79.         //
  80.         // public void setTarget(Object target) {
  81.         // this.target = target;
  82.         // }
  83.         //
  84.         // public Advice getAdvice() {
  85.         // return advice;
  86.         // }
  87.         //
  88.         // public void setAdvice(Advice advice) {
  89.         // this.advice = advice;
  90.         // }

  91. }

  92. public class AdviceTest {

  93.         public static void main(String[] args) {
  94.                 Advice ai = (Advice) new ProxyFactory().createProxy();
  95.                 ai.print();
  96.         }

  97. }
复制代码
回复 使用道具 举报
马镱洵 发表于 2012-9-6 14:32
你这个方法是不是写错了,再说你这个方法是多余的(这个方法和setAdvice()方法与setTarget()方法重复了),你的 ...
  1.   public Object getProxy(Object target,Advice advice) {
  2.                 this.target = target;
  3.                 this.advice = advice;
  4.                 return getProxy();
  5.         }
复制代码
呵呵 你说的对啊,这个方法确实写错了,我想写一个重载的,一时糊涂搞成这个样子了,
  1. public Object createProxy(Object target,Advice advice) {
  2.       this.target = target;
  3.       this.advice = advice;
  4.       return
  5. createProxy ();
  6. }
复制代码
不是需要转为Advice接口,而是把被代理对象传递过来,就是那个target,然后转为被代理对象所实现的那个接口使用
比如接口
  1. public inteface ITest {
  2.      void test();
  3. }
复制代码
实现类ITestImpl
  1. public class ITestImpl  implements ITest{
  2.       void test() {
  3.            System.out.println("黑马");
  4.        }
  5. }
复制代码
AdviceImpl
  1. public class AdviceImpl implements Advice {
  2.        
  3.         @Override
  4.         public void before(Object proxy, Method method, Object[] args) {
  5.                 System.out.println("before");
  6.         }

  7.         @Override
  8.         public void after(Object proxy, Method method, Object[] args) {
  9.                 System.out.println("after");
  10.                 //为了测试处理异常的方法是否执行,自己搞出来一个异常
  11.                 Integer.parseInt("黑马程序员");
  12.         }

  13.         @Override
  14.         public void exception(Object proxy, Method method, Object[] args) {
  15.                 System.out.println("exception");
  16.         }

  17.         @Override
  18.         public void beforeAndAfter(Object proxy, Method method, Object[] args) {
  19.                 System.out.println("beforeAndAfter");
  20.         }

  21. }
复制代码
测试代码,
  1. <blockquote>public class Test {
复制代码
输出的结果:
beforeAndAfter
before
黑马
after
exception


回复 使用道具 举报
佟亚鹏 发表于 2012-9-6 18:23
呵呵 你说的对啊,这个方法确实写错了,我想写一个重载的,一时糊涂搞成这个样子了,不是需要转为Advice ...

"不是需要转为Advice接口,而是把被代理对象传递过来,就是那个target,然后转为被代理对象所实现的那个接口使用"

我的意思就是说:需要把被代理的真实对象转换为它所实现的那个接口,然后再通过这个接口的引用,调用接口中所定义的方法,当然,接口中定义的方法都是抽象方法,实际上是调用的被代理的对象所实现接口的相对应的方法.
比如说:
  1. ITest t= (ITest) new ProxyFactory().createProxy();
  2.                 t.test();
复制代码
这里只能将取得的真实被代理对象强转为ITest接口,再通过接口的引用来调用test()方法.
如果要是将取得的真实被代理对象强转为ITestImpl实现类,再通过强转后的ITestImpl类的引用来调用test()方法,就会报错.
回复 使用道具 举报
嗯对  只能转为他所现在的接口哦,你的速度好快啊,呵呵
回复 使用道具 举报
  1. public Object createProxy(Object target,Advice advice) {
  2.       this.target = target;
  3.       this.advice = advice;
  4.       return
  5. createProxy ();
  6. }
复制代码
return createProxy ();
这个return语句用来干什么用的?你是用来返回真实的被代理对象吗?
真实的被代理的对象是通过Proxy.newProxyInstance()方法取得的,而不是自己写的.你只能是说需要定义一个实现了某个接口的实现类,然后Proxy.newProxyInstance()方法的参数里需要用到这个实现类的对象(你的代码中,target就是实现了Advice接口的类的对象.),请看代码:
  1. public static Object newProxyInstance(ClassLoader loader,
  2.                                       Class<?>[] interfaces,
  3.                                       InvocationHandler h)
复制代码
第一个参数loader(就是实现了Advice接口的实现类所属的Class对象的类加载器),就应该为target.getClass().getClassLoader().
第二个参数interfaces(可以是target对象所实现的所有接口的Class对象,也可以是单独一人接口的Class对象.),按照你前面代码的流程,那么此处就应该为target.getClass().getInterfaces().
第三个参数h(就是需要传入一个实现了InvocationHandler接口的对象,不过你在前面的代码中是传入的一个匿名类对象,当然效果一样.),这个InvocationHandler接口里的invoke()方法就是JDK动态代理模式的核心了.
回复 使用道具 举报
佟亚鹏 发表于 2012-9-6 18:23
呵呵 你说的对啊,这个方法确实写错了,我想写一个重载的,一时糊涂搞成这个样子了,不是需要转为Advice ...
  1. public class AdviceImpl implements Advice {
  2.         
  3.         @Override
  4.         public void before(Object proxy, Method method, Object[] args) {
  5.                 System.out.println("before");
  6.         }

  7.         @Override
  8.         public void after(Object proxy, Method method, Object[] args) {
  9.                 System.out.println("after");
  10.                 //为了测试处理异常的方法是否执行,自己搞出来一个异常
  11.                 Integer.parseInt("黑马程序员");
  12.         }

  13.         @Override
  14.         public void exception(Object proxy, Method method, Object[] args) {
  15.                 System.out.println("exception");
  16.         }

  17.         @Override
  18.         public void beforeAndAfter(Object proxy, Method method, Object[] args) {
  19.                 System.out.println("beforeAndAfter");
  20.         }

  21. }
复制代码
另外,你这四个方法中的参数全是多余的吧,根本用不上的.
回复 使用道具 举报
马镱洵 发表于 2012-9-6 19:06
另外,你这四个方法中的参数全是多余的吧,根本用不上的.

那个return  返回createProxy()中产生的代理,是createProxy()的重载,另外那些个参数是有意思的,只是例子程序中没有用到而已,你可以把方法名,参数打印出来,看看结果,这些参数,如果需要的话可以在Advice中进行处理下,这个只是对jdk的动态代理进行了封装,为了就是使编程接口变的好用一些,这个类是我自己写的模仿spring的框架中拿出来的,它的原貌在哪个附件中有哦
回复 使用道具 举报
佟亚鹏 发表于 2012-9-6 19:32
那个return  返回createProxy()中产生的代理,是createProxy()的重载,另外那些个参数是有意思的,只是例 ...


"另外那些个参数是有意思的,只是例子程序中没有用到而已,你可以把方法名,参数打印出来"

你要打印方法名,参数名,也不需要在接口中的方法定义那些参数啊,这些功能是在InvocationHandler接口的invoke()方法里实现的啊,见代码:
  1. public Object createProxy() {
  2.                 AdviceImpl adviceImpl = new AdviceImpl();
  3.                 getProxy(adviceImpl, adviceImpl);
  4.                 Object proxyObj = Proxy.newProxyInstance(target.getClass()
  5.                                 .getClassLoader(), target.getClass().getInterfaces(),
  6.                                 new InvocationHandler() {
  7.                                         @Override
  8.                                         public Object invoke(Object proxy, Method method,
  9.                                                         Object[] args) throws Throwable {
  10.                                                 Object result = null;
  11.                                                 try {
  12.                                                         advice.beforeAndAfter();
  13.                                                         advice.before();
  14.                                                         result = method.invoke(target, args);
  15.                                                         advice.after();
  16.                                                         advice.beforeAndAfter();

  17.                                                         // 这句代码就是打印方法名了
  18.                                                         System.out.println(method.getName());
  19.                                                 } catch (Exception e) {
  20.                                                         advice.exception();
  21.                                                 }
  22.                                                 return result;
  23.                                         }
  24.                                 });
  25.                 return proxyObj;
  26.         }
复制代码
回复 使用道具 举报
马镱洵 发表于 2012-9-6 19:38
"另外那些个参数是有意思的,只是例子程序中没有用到而已,你可以把方法名,参数打印出来"

你要打印方法 ...

怎么给你说呢,这个产生代理的类,写好就不改的,把所有的处理逻辑都放在Advice,那个类只是一个工具类而已,比如说,使用spring,想加点逻辑不至于去修改它的源码吧
回复 使用道具 举报
佟亚鹏 发表于 2012-9-6 19:44
怎么给你说呢,这个产生代理的类,写好就不改的,把所有的处理逻辑都放在Advice,那个类只是一个工具类而 ...

我只是说Advice接口中那四个方法的参数是多余的,要获取方法名,参数名什么的都是直接在InvocationHandler接口中的invoke()方法实现的.
跟你说的这些没有任何关系啊.你还不是一样可以把所有的处理逻辑放在Advice接口中,你要弄明白的是,我只是强调:
你的Advice接口中定义的方法中的参数,不需要Object proxy,Method method,Object[] args这三个参数.
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马