精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-05-22
引言: 继前一节(面向方法编程AOP学习之二 —— “原始时代” )的学习引发了一些思考,如前面总结所说的,商人老板无法接受为了一个表演家,就要造一个剧院,这样的成本实在太高太高了,这里需要做的是一个剧院可以允许不同的表演者表演不同的节目,这才是真正的一种进化 ,才是一种进步 。
主题: JDK的动态代理
描述: 在JDK1.3开始,就出现了动态代理的实现,jdk提供了java.lang.reflect.InvocationHandler这么样的一个接口来动态的实现,在执行某方法时,去处理一些事情。
场景制造: 如前一节的场景,这个老板又找到了一个新的表演家,这个表演家不仅仅只会一个表演能力,他会吉他,会钢琴。这时,老板把他带到了一个大的剧院里面,这里面的设备齐全,道具都有都,任由表演家天马行空。
角色: # 多才的表演家:Player2 # 老板:Boss # 设备齐全的剧院:DynaProxyTheatre
作用:
/** * 表演家接口 */ public interface IPlayer2 { public void playPiano(); public void playGuitar(); }
package chat3; /** * 很会赚钱的老板 */ public class Boss { /** * 卖票 */ public void shellTicket() { System.out.println("shell many tickets "); } /** * 给酬劳 */ public void givePlayerMoney() { System.out.println("give a little money to player."); } /** * 逃跑 */ public void runAway() { System.out.println("The play is broken , the boss run away in a hurry"); } }
package chat3; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 可变式接收各种表演者<br> * 对剧院对各种表演者都可以支持 */ public class DynaProxyTheatre implements InvocationHandler { /** * 目标的表演者 */ public Object targetPlayer; /** * 用来接收目标表演者 * * @param target * 表演者 * @return 返回代理的接口 */ public Object bind(Object target) { this.targetPlayer = target; return Proxy.newProxyInstance(targetPlayer.getClass().getClassLoader(), targetPlayer.getClass().getInterfaces(), this); } /** * 演出开始 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; Boss boss = new Boss(); boss.shellTicket(); System.out.println(" begin =>" + method.getName()); try { // 动态调用方法 result = method.invoke(targetPlayer, args); } catch (Exception e) { boss.runAway(); } System.out.println(" end =>" + method.getName()); boss.givePlayerMoney(); return result; } } 来一场演出吧
@Test public void testChat3() { IPlayer2 player2 = (IPlayer2) new DynaProxyTheatre() .bind(new Player2()); player2.playGuitar(); player2.playPiano(); }
演出过程
shell many tickets begin =>playGuitar playing guitar... end =>playGuitar give a little money to player. shell many tickets begin =>playPiano playing piano... end =>playPiano give a little money to player.
总结1: JDK的动态代理,把从重复的编写代理类带到了一个动态的代理类中。可以为不同的方法接口都进行处理。就这样,剧院和表演家的关系进行了一次解耦了。 但这里面还是有一个的问题,代理者(剧院)与切入处理者(Boss)并没有解耦掉。
作用变换:
老板的变换(Boss2) package chat3; import java.lang.reflect.Method; /** * 很会赚钱的老板 */ public class Boss2 implements IBoss { public void shellTicket(Method method) { System.out.println("shell many tickets "); } public void givePlayerMoney(Method method) { System.out.println("give a little money to player."); } public void runAway(Method method) { System.out.println("The play is broken , the boss run away in a hurry"); } }
剧场的变换(DynaProxyTheatre2):
package chat3; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 可变式接收各种表演者<br> * 对剧院对各种表演者都可以支持 */ public class DynaProxyTheatre2 implements InvocationHandler { /** * 目标的表演者 */ public Object targetPlayer; /** * 用来接收Boss的到来 */ public Object proxy; /** * 用来接收目标表演者 * * @param target表演者 * @param proxy 切入的处理者(Boss) * @return 返回代理的接口 */ public Object bind(Object target, Object proxy) { this.targetPlayer = target; this.proxy = proxy; return Proxy.newProxyInstance(targetPlayer.getClass().getClassLoader(), targetPlayer.getClass().getInterfaces(), this); } /** * 演出开始 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; // 代理与切入处理者的解耦调用方法 Class shellTicket = this.proxy.getClass(); // 反射得到操作者的shellTicket方法 Method start = shellTicket.getDeclaredMethod("shellTicket", new Class[] { Method.class }); // 反射执行shellTicket方法 start.invoke(this.proxy, new Object[] { method }); System.out.println(" begin =>" + method.getName()); try { // 动态调用方法 result = method.invoke(targetPlayer, args); } catch (Exception e) { Method runAway = shellTicket.getDeclaredMethod("runAway", new Class[] {}); runAway.invoke(this.proxy, new Object[] { method }); } System.out.println(" end =>" + method.getName()); Method givePlayerMoney = shellTicket.getDeclaredMethod( "givePlayerMoney", new Class[] { Method.class }); givePlayerMoney.invoke(this.proxy, new Object[] { method }); return result; } }
再一次的演出:
同上
演示结果:
shell many tickets begin =>playGuitar playing guitar... end =>playGuitar give a little money to player. shell many tickets begin =>playPiano playing piano... end =>playPiano give a little money to player.
总结2: 从第二步,进入了新的改造,在这里,把剧院(代理类)和老板(切入处理类),进行了解耦。当然,在这基础上的更进一步的实现,封装还可以使我们在使用AOP的过程更加的简单,便捷。这也就是后面Spring与AspectJ这些AOP框架所体现的进步性。
下一节:待续....
此刻窗外看去,杭州正沉溺在细雨濛濛之中...
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-05-27
楼主请用jdk动态代理个没有接口的普通类试试
|
|
返回顶楼 | |
发表时间:2011-05-27
icezx 写道 楼主请用jdk动态代理个没有接口的普通类试试 这样子是不可以的, [url] public Object bind(Object target) { this.targetPlayer = target; return Proxy.newProxyInstance(targetPlayer.getClass().getClassLoader(), targetPlayer.getClass().getInterfaces(), this); } [/url] 这里是传进这个普通类的接口进去做代理的,接口是必需的。 |
|
返回顶楼 | |
发表时间:2011-05-30
sammor 写道 icezx 写道 楼主请用jdk动态代理个没有接口的普通类试试
这样子是不可以的, [url] public Object bind(Object target) { this.targetPlayer = target; return Proxy.newProxyInstance(targetPlayer.getClass().getClassLoader(), targetPlayer.getClass().getInterfaces(), this); } [/url] 这里是传进这个普通类的接口进去做代理的,接口是必需的。 实际开发中接口不是必须的哦,也就jdk是必须的而已。 |
|
返回顶楼 | |
发表时间:2011-05-31
icezx 写道 实际开发中接口不是必须的哦,也就jdk是必须的而已。 没能理解你这句话的意思哦,能再解释清楚点吗? |
|
返回顶楼 | |
发表时间:2011-06-02
icezx 写道 楼主请用jdk动态代理个没有接口的普通类试试
可以的,用cglib可以实现的。 |
|
返回顶楼 | |
浏览 2337 次