论坛首页 Java企业应用论坛

面向方法编程AOP学习之三 —— “进化论”

浏览 2291 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-05-22  

引言:

       继前一节(面向方法编程AOP学习之二 —— “原始时代” )的学习引发了一些思考,如前面总结所说的,商人老板无法接受为了一个表演家,就要造一个剧院,这样的成本实在太高太高了,这里需要做的是一个剧院可以允许不同的表演者表演不同的节目,这才是真正的一种进化 ,才是一种进步

 

主题:

       JDK的动态代理

 

描述:

       在JDK1.3开始,就出现了动态代理的实现,jdk提供了java.lang.reflect.InvocationHandler这么样的一个接口来动态的实现,在执行某方法时,去处理一些事情。

 

场景制造:

       如前一节的场景,这个老板又找到了一个新的表演家,这个表演家不仅仅只会一个表演能力,他会吉他,会钢琴。这时,老板把他带到了一个大的剧院里面,这里面的设备齐全,道具都有都,任由表演家天马行空。

 

角色:

# 多才的表演家:Player2
# 老板:Boss  
# 设备齐全的剧院:DynaProxyTheatre

 

作用:

  • 多才的表演家:Player2
/**
 * 表演家接口
 */
public interface IPlayer2 {

	public void playPiano();

	public void playGuitar();
}
  •  老板(Boss)
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");
	}
}
  •  设备齐全的剧院(DynaProxyTheatre)
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框架所体现的进步性。

 

下一节:待续....

 

此刻窗外看去,杭州正沉溺在细雨濛濛之中...

 

   发表时间:2011-05-27  
楼主请用jdk动态代理个没有接口的普通类试试
0 请登录后投票
   发表时间: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]

这里是传进这个普通类的接口进去做代理的,接口是必需的。
0 请登录后投票
   发表时间: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是必须的而已。
0 请登录后投票
   发表时间:2011-05-31  
icezx 写道

实际开发中接口不是必须的哦,也就jdk是必须的而已。


没能理解你这句话的意思哦,能再解释清楚点吗?
0 请登录后投票
   发表时间:2011-06-02  
icezx 写道
楼主请用jdk动态代理个没有接口的普通类试试

可以的,用cglib可以实现的。
0 请登录后投票
论坛首页 Java企业应用版

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