<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title><![CDATA[Java伴侣 - EJB&Spring]]></title>
<link>http://www.javamilk.org/</link>
<description><![CDATA[关于工作、学习与生活]]></description>
<language>zh-cn</language>
<copyright><![CDATA[Copyright 2005 PBlog3 v2.8]]></copyright>
<webMaster><![CDATA[blurxx@yahoo.cn(Blur)]]></webMaster>
<generator>PBlog2 v2.4</generator> 
<image>
	<title>Java伴侣</title>
	<url>http://www.javamilk.org/images/logos.gif</url>
	<link>http://www.javamilk.org/</link>
	<description>Java伴侣</description>
</image>

			<item>
			<link>http://www.javamilk.org/article.asp?id=816</link>
			<title><![CDATA[反射实现AOP 动态代理模式(Spring AOP 的实现原理)]]></title>
			<author>blurxx@yahoo.cn(Java伴侣)</author>
			<category><![CDATA[EJB&amp;Spring]]></category>
			<pubDate>Fri,01 Aug 2008 19:29:00 +0800</pubDate>
			<guid>http://www.javamilk.org/default.asp?id=816</guid>
		<description><![CDATA[好长时间没有用过Spring了. 突然拿起书.我都发现自己对AOP都不熟悉了.<br/>其实AOP的意思就是面向切面编程.<br/>OO注重的是我们解决问题的方法(封装成Method),而AOP注重的是许多解决解决问题的方法中的共同点,是对OO思想的一种补充!<br/>还是拿人家经常举的一个例子讲解一下吧:<br/>比如说,我们现在要开发的一个应用里面有很多的业务方法,但是,我们现在要对这个方法的执行做全面监控,或部分监控.也许我们就会在要一些方法前去加上一条日志记录,<br/>我们写个例子看看我们最简单的解决方案<br/>我们先写一个接口IHello.java代码如下:<br/> <br/><br/> <div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code73785);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code73785>1package sinosoft.dj.aop.staticaop;<br/> 2<br/> 3public interface IHello {<br/> 4&nbsp;&nbsp;&nbsp;&nbsp;/** *//**<br/> 5&nbsp;&nbsp;&nbsp;&nbsp; * 假设这是一个业务方法<br/> 6&nbsp;&nbsp;&nbsp;&nbsp; * @param name<br/> 7&nbsp;&nbsp;&nbsp;&nbsp; */<br/> 8&nbsp;&nbsp;&nbsp;&nbsp;void sayHello(String name);<br/> 9}<br/>10</div></div><br/><br/>里面有个方法,用于输入&#34;Hello&#34; 加传进来的姓名;我们去写个类实现IHello接口<br/> <br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code65499);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code65499>package sinosoft.dj.aop.staticaop;<br/><br/>public class Hello implements IHello {<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;public void sayHello(String name) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&#34;Hello &#34; + name);<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>}</div></div><br/><br/><br/>现在我们要为这个业务方法加上日志记录的业务,我们在不改变原代码的情况下,我们会去怎么做呢?也许,你会去写一个类去实现IHello接口,并依赖Hello这个类.代码如下:<br/> <br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code43472);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code43472><br/> 1package sinosoft.dj.aop.staticaop;<br/> 2<br/> 3public class HelloProxy implements IHello {<br/> 4&nbsp;&nbsp;&nbsp;&nbsp;private IHello hello;<br/> 5<br/> 6&nbsp;&nbsp;&nbsp;&nbsp;public HelloProxy(IHello hello) {<br/> 7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.hello = hello;<br/> 8&nbsp;&nbsp;&nbsp;&nbsp;}<br/> 9<br/>10&nbsp;&nbsp;&nbsp;&nbsp;public void sayHello(String name) {<br/>11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Logger.logging(Level.DEBUGE, &#34;sayHello method start.&#34;);<br/>12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hello.sayHello(name);<br/>13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Logger.logging(Level.INFO, &#34;sayHello method end!&#34;);<br/>14<br/>15&nbsp;&nbsp;&nbsp;&nbsp;}<br/>16<br/>17}<br/>18</div></div><br/><br/>其中.Logger类和Level枚举代码如下:<br/>Logger.java<br/> <br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code82993);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code82993><br/> 1package sinosoft.dj.aop.staticaop;<br/> 2<br/> 3import java.util.Date;<br/> 4<br/> 5public class Logger{<br/> 6&nbsp;&nbsp;&nbsp;&nbsp;/** *//**<br/> 7&nbsp;&nbsp;&nbsp;&nbsp; * 根据等级记录日志<br/> 8&nbsp;&nbsp;&nbsp;&nbsp; * @param level<br/> 9&nbsp;&nbsp;&nbsp;&nbsp; * @param context<br/>10&nbsp;&nbsp;&nbsp;&nbsp; */<br/>11&nbsp;&nbsp;&nbsp;&nbsp;public static void logging(Level level, String context) {<br/>12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (level.equals(Level.INFO)) {<br/>13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(new Date().toLocaleString() + &#34; &#34; + context);<br/>14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (level.equals(Level.DEBUGE)) {<br/>16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.err.println(new Date() + &#34; &#34; + context);<br/>17&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>18&nbsp;&nbsp;&nbsp;&nbsp;}<br/>19<br/>20}<br/>21</div></div><br/><br/>Level.java<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code64430);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code64430>1package sinosoft.dj.aop.staticaop;<br/>2<br/>3public enum Level {<br/>4&nbsp;&nbsp;&nbsp;&nbsp;INFO,DEBUGE;<br/>5}<br/>6</div></div><br/><br/>那我们去写个测试类看看,代码如下:<br/>Test.java<br/> <br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code46677);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code46677>1package sinosoft.dj.aop.staticaop;<br/>2<br/>3public class Test {<br/>4&nbsp;&nbsp;&nbsp;&nbsp;public static void main(String[] args) {<br/>5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IHello hello = new HelloProxy(new Hello());<br/>6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hello.sayHello(&#34;Doublej&#34;);<br/>7&nbsp;&nbsp;&nbsp;&nbsp;}<br/>8}<br/>9</div></div>运行以上代码我们可以得到下面结果:<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code73380);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code73380>Tue Mar 04 20:57:12 CST 2008 sayHello method start.<br/>Hello Doublej<br/>2008-3-4 20:57:12 sayHello method end!</div></div><br/><br/>从上面的代码我们可以看出,hello对象是被HelloProxy这个所谓的代理态所创建的.这样,如果我们以后要把日志记录的功能去掉.那我们只要把得到hello对象的代码改成以下:<br/> <br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code93270);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code93270>1package sinosoft.dj.aop.staticaop;<br/>2<br/>3public class Test {<br/>4&nbsp;&nbsp;&nbsp;&nbsp;public static void main(String[] args) {<br/>5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IHello hello = new Hello();<br/>6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hello.sayHello(&#34;Doublej&#34;);<br/>7&nbsp;&nbsp;&nbsp;&nbsp;}<br/>8}<br/>9</div></div><br/><br/>上面代码,可以说是AOP最简单的实现!<br/>但是我们会发现一个问题,如果我们像Hello这样的类很多,那么,我们是不是要去写很多个HelloProxy这样的类呢.没错,是的.其实也是一种很麻烦的事.在jdk1.3以后.jdk跟我们提供了一个API&nbsp;&nbsp; java.lang.reflect.InvocationHandler的类. 这个类可以让我们在JVM调用某个类的方法时动态的为些方法做些什么事.让我们把以上的代码改一下来看看效果.<br/>同样,我们写一个IHello的接口和一个Hello的实现类.在接口中.我们定义两个方法;代码如下 :<br/><br/>IHello.java<br/> <br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code60158);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code60158> 1package sinosoft.dj.aop.proxyaop;<br/> 2<br/> 3public interface IHello {<br/> 4&nbsp;&nbsp;&nbsp;&nbsp;/** *//**<br/> 5&nbsp;&nbsp;&nbsp;&nbsp; * 业务处理A方法<br/> 6&nbsp;&nbsp;&nbsp;&nbsp; * @param name<br/> 7&nbsp;&nbsp;&nbsp;&nbsp; */<br/> 8&nbsp;&nbsp;&nbsp;&nbsp;void sayHello(String name);<br/> 9&nbsp;&nbsp;&nbsp;&nbsp;/** *//**<br/>10&nbsp;&nbsp;&nbsp;&nbsp; * 业务处理B方法<br/>11&nbsp;&nbsp;&nbsp;&nbsp; * @param name<br/>12&nbsp;&nbsp;&nbsp;&nbsp; */<br/>13&nbsp;&nbsp;&nbsp;&nbsp;void sayGoogBye(String name);<br/>14}<br/>15</div></div><br/><br/><br/>Hello.java <br/> <br/><br/> <div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code59494);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code59494>1package sinosoft.dj.aop.proxyaop;<br/> 2<br/> 3public class Hello implements IHello {<br/> 4<br/> 5&nbsp;&nbsp;&nbsp;&nbsp;public void sayHello(String name) {<br/> 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&#34;Hello &#34; + name);<br/> 7&nbsp;&nbsp;&nbsp;&nbsp;}<br/> 8&nbsp;&nbsp;&nbsp;&nbsp;public void sayGoogBye(String name) {<br/> 9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(name+&#34; GoodBye!&#34;);<br/>10&nbsp;&nbsp;&nbsp;&nbsp;}<br/>11}<br/>12</div></div><br/><br/>我们一样的去写一个代理类.只不过.让这个类去实现java.lang.reflect.InvocationHandler接口,代码如下:<br/> <br/><br/> <div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code34927);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code34927>1package sinosoft.dj.aop.proxyaop;<br/> 2<br/> 3import java.lang.reflect.InvocationHandler;<br/> 4import java.lang.reflect.Method;<br/> 5import java.lang.reflect.Proxy;<br/> 6<br/> 7public class DynaProxyHello implements InvocationHandler {<br/> 8<br/> 9&nbsp;&nbsp;&nbsp;&nbsp;/** *//**<br/>10&nbsp;&nbsp;&nbsp;&nbsp; * 要处理的对象(也就是我们要在方法的前后加上业务逻辑的对象,如例子中的Hello)<br/>11&nbsp;&nbsp;&nbsp;&nbsp; */<br/>12&nbsp;&nbsp;&nbsp;&nbsp;private Object delegate;<br/>13<br/>14&nbsp;&nbsp;&nbsp;&nbsp;/** *//**<br/>15&nbsp;&nbsp;&nbsp;&nbsp; * 动态生成方法被处理过后的对象 (写法固定)<br/>16&nbsp;&nbsp;&nbsp;&nbsp; * <br/>17&nbsp;&nbsp;&nbsp;&nbsp; * @param delegate<br/>18&nbsp;&nbsp;&nbsp;&nbsp; * @param proxy<br/>19&nbsp;&nbsp;&nbsp;&nbsp; * @return<br/>20&nbsp;&nbsp;&nbsp;&nbsp; */<br/>21&nbsp;&nbsp;&nbsp;&nbsp;public Object bind(Object delegate) {<br/>22&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.delegate = delegate;<br/>23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Proxy.newProxyInstance(<br/>24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.delegate.getClass().getClassLoader(), this.delegate<br/>25&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.getClass().getInterfaces(), this);<br/>26&nbsp;&nbsp;&nbsp;&nbsp;}<br/>27&nbsp;&nbsp;&nbsp;&nbsp;/** *//**<br/>28&nbsp;&nbsp;&nbsp;&nbsp; * 要处理的对象中的每个方法会被此方法送去JVM调用,也就是说,要处理的对象的方法只能通过此方法调用<br/>29&nbsp;&nbsp;&nbsp;&nbsp; * 此方法是动态的,不是手动调用的<br/>30&nbsp;&nbsp;&nbsp;&nbsp; */<br/>31&nbsp;&nbsp;&nbsp;&nbsp;public Object invoke(Object proxy, Method method, Object[] args)<br/>32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws Throwable {<br/>33&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object result = null;<br/>34&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<br/>35&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//执行原来的方法之前记录日志<br/>36&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Logger.logging(Level.DEBUGE, method.getName() + &#34; Method end .&#34;);<br/>37&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>38&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//JVM通过这条语句执行原来的方法(反射机制)<br/>39&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = method.invoke(this.delegate, args);<br/>40&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//执行原来的方法之后记录日志<br/>41&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Logger.logging(Level.INFO, method.getName() + &#34; Method Start!&#34;);<br/>42&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (Exception e) {<br/>43&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br/>44&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>45&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//返回方法返回值给调用者<br/>46&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return result;<br/>47&nbsp;&nbsp;&nbsp;&nbsp;}<br/>48<br/>49}<br/>50</div></div><br/><br/>上面类中出现的Logger类和Level枚举还是和上一上例子的实现是一样的.这里就不贴出代码了.<br/><br/>让我们写一个Test类去测试一下.代码如下:<br/>Test.java<br/> <br/><br/> <div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code8628);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code8628>1package sinosoft.dj.aop.proxyaop;<br/> 2<br/> 3public class Test {<br/> 4&nbsp;&nbsp;&nbsp;&nbsp;public static void main(String[] args) {<br/> 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IHello hello = (IHello)new DynaProxyHello().bind(new Hello());<br/> 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hello.sayGoogBye(&#34;Double J&#34;);<br/> 7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hello.sayHello(&#34;Double J&#34;);<br/> 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/> 9&nbsp;&nbsp;&nbsp;&nbsp;}<br/>10}<br/>11</div></div><br/><br/>运行输出的结果如下:<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code60967);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code60967>Tue Mar 04 21:24:03 CST 2008 sayGoogBye Method end .<br/>Double J GoodBye!<br/>2008-3-4 21:24:03 sayGoogBye Method Start!<br/>Tue Mar 04 21:24:03 CST 2008 sayHello Method end .<br/>Hello Double J<br/>2008-3-4 21:24:03 sayHello Method Start!</div></div><br/><br/>由于线程的关系,第二个方法的开始出现在第一个方法的结束之前.这不是我们所关注的!<br/>从上面的例子我们看出.只要你是采用面向接口编程,那么,你的任何对象的方法执行之前要加上记录日志的操作都是可以的.他(DynaPoxyHello)自动去代理执行被代理对象(Hello)中的每一个方法,一个java.lang.reflect.InvocationHandler接口就把我们的代理对象和被代理对象解藕了.但是,我们又发现还有一个问题,这个DynaPoxyHello对象只能跟我们去在方法前后加上日志记录的操作.我们能不能把DynaPoxyHello对象和日志操作对象(Logger)解藕呢?<br/>结果是肯定的.让我们来分析一下我们的需求.<br/>我们要在被代理对象的方法前面或者后面去加上日志操作代码(或者是其它操作的代码),<br/>那么,我们可以抽象出一个接口,这个接口里就只有两个方法,一个是在被代理对象要执行方法之前执行的方法,我们取名为start,第二个方法就是在被代理对象执行方法之后执行的方法,我们取名为end .接口定义如下 :<br/> <br/><br/> <div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code3951);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code3951>1package sinosoft.dj.aop.proxyaop;<br/> 2<br/> 3import java.lang.reflect.Method;<br/> 4<br/> 5public interface IOperation {<br/> 6&nbsp;&nbsp;&nbsp;&nbsp;/** *//**<br/> 7&nbsp;&nbsp;&nbsp;&nbsp; * 方法执行之前的操作<br/> 8&nbsp;&nbsp;&nbsp;&nbsp; * @param method<br/> 9&nbsp;&nbsp;&nbsp;&nbsp; */<br/>10&nbsp;&nbsp;&nbsp;&nbsp;void start(Method method);<br/>11&nbsp;&nbsp;&nbsp;&nbsp;/** *//**<br/>12&nbsp;&nbsp;&nbsp;&nbsp; * 方法执行之后的操作<br/>13&nbsp;&nbsp;&nbsp;&nbsp; * @param method<br/>14&nbsp;&nbsp;&nbsp;&nbsp; */<br/>15&nbsp;&nbsp;&nbsp;&nbsp;void end(Method method);<br/>16}<br/>17</div></div><br/><br/>我们去写一个实现上面接口的类.我们把作他真正的操作者,如下面是日志操作者的一个类:<br/>LoggerOperation.java<br/> <br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code28114);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code28114>package sinosoft.dj.aop.proxyaop;<br/><br/>import java.lang.reflect.Method;<br/><br/>public class LoggerOperation implements IOperation {<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;public void end(Method method) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Logger.logging(Level.DEBUGE, method.getName() + &#34; Method end .&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;public void start(Method method) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Logger.logging(Level.INFO, method.getName() + &#34; Method Start!&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>}</div></div><br/><br/><br/>然后我们要改一下代理对象DynaProxyHello中的代码.如下:<br/> <br/><br/> <div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code55626);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code55626>1package sinosoft.dj.aop.proxyaop;<br/> 2<br/> 3import java.lang.reflect.InvocationHandler;<br/> 4import java.lang.reflect.Method;<br/> 5import java.lang.reflect.Proxy;<br/> 6<br/> 7public class DynaProxyHello implements InvocationHandler {<br/> 8&nbsp;&nbsp;&nbsp;&nbsp;/** *//**<br/> 9&nbsp;&nbsp;&nbsp;&nbsp; * 操作者<br/>10&nbsp;&nbsp;&nbsp;&nbsp; */<br/>11&nbsp;&nbsp;&nbsp;&nbsp;private Object proxy;<br/>12&nbsp;&nbsp;&nbsp;&nbsp;/** *//**<br/>13&nbsp;&nbsp;&nbsp;&nbsp; * 要处理的对象(也就是我们要在方法的前后加上业务逻辑的对象,如例子中的Hello)<br/>14&nbsp;&nbsp;&nbsp;&nbsp; */<br/>15&nbsp;&nbsp;&nbsp;&nbsp;private Object delegate;<br/>16<br/>17&nbsp;&nbsp;&nbsp;&nbsp;/** *//**<br/>18&nbsp;&nbsp;&nbsp;&nbsp; * 动态生成方法被处理过后的对象 (写法固定)<br/>19&nbsp;&nbsp;&nbsp;&nbsp; * <br/>20&nbsp;&nbsp;&nbsp;&nbsp; * @param delegate<br/>21&nbsp;&nbsp;&nbsp;&nbsp; * @param proxy<br/>22&nbsp;&nbsp;&nbsp;&nbsp; * @return<br/>23&nbsp;&nbsp;&nbsp;&nbsp; */<br/>24&nbsp;&nbsp;&nbsp;&nbsp;public Object bind(Object delegate,Object proxy) {<br/>25&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>26&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.proxy = proxy;<br/>27&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.delegate = delegate;<br/>28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Proxy.newProxyInstance(<br/>29&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.delegate.getClass().getClassLoader(), this.delegate<br/>30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.getClass().getInterfaces(), this);<br/>31&nbsp;&nbsp;&nbsp;&nbsp;}<br/>32&nbsp;&nbsp;&nbsp;&nbsp;/** *//**<br/>33&nbsp;&nbsp;&nbsp;&nbsp; * 要处理的对象中的每个方法会被此方法送去JVM调用,也就是说,要处理的对象的方法只能通过此方法调用<br/>34&nbsp;&nbsp;&nbsp;&nbsp; * 此方法是动态的,不是手动调用的<br/>35&nbsp;&nbsp;&nbsp;&nbsp; */<br/>36&nbsp;&nbsp;&nbsp;&nbsp;public Object invoke(Object proxy, Method method, Object[] args)<br/>37&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws Throwable {<br/>38&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object result = null;<br/>39&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<br/>40&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//反射得到操作者的实例<br/>41&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class clazz = this.proxy.getClass();<br/>42&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//反射得到操作者的Start方法<br/>43&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Method start = clazz.getDeclaredMethod(&#34;start&#34;,<br/>44&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new Class[] { Method.class });<br/>45&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//反射执行start方法<br/>46&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start.invoke(this.proxy, new Object[] { method });<br/>47&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//执行要处理对象的原本方法<br/>48&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = method.invoke(this.delegate, args);<br/>49//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;反射得到操作者的end方法<br/>50&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Method end = clazz.getDeclaredMethod(&#34;end&#34;,<br/>51&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new Class[] { Method.class });<br/>52//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;反射执行end方法<br/>53&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end.invoke(this.proxy, new Object[] { method });<br/>54<br/>55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (Exception e) {<br/>56&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br/>57&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>58&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return result;<br/>59&nbsp;&nbsp;&nbsp;&nbsp;}<br/>60<br/>61}<br/>62</div></div><br/><br/>然后我们把Test.java中的代码改一下.测试一下:<br/> <br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code19973);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code19973>package sinosoft.dj.aop.proxyaop;<br/><br/>public class Test {<br/>&nbsp;&nbsp;&nbsp;&nbsp;public static void main(String[] args) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IHello hello = (IHello)new DynaProxyHello().bind(new Hello(),new LoggerOperation());<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hello.sayGoogBye(&#34;Double J&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hello.sayHello(&#34;Double J&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>}</div></div><br/><br/>结果还是一样的吧.<br/><br/>如果你想在每个方法之前加上日志记录,而不在方法后加上日志记录.你就把LoggerOperation类改成如下:<br/> <br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code53490);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code53490> 1package sinosoft.dj.aop.proxyaop;<br/> 2<br/> 3import java.lang.reflect.Method;<br/> 4<br/> 5public class LoggerOperation implements IOperation {<br/> 6<br/> 7&nbsp;&nbsp;&nbsp;&nbsp;public void end(Method method) {<br/> 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Logger.logging(Level.DEBUGE, method.getName() + &#34; Method end .&#34;);<br/> 9&nbsp;&nbsp;&nbsp;&nbsp;}<br/>10<br/>11&nbsp;&nbsp;&nbsp;&nbsp;public void start(Method method) {<br/>12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Logger.logging(Level.INFO, method.getName() + &#34; Method Start!&#34;);<br/>13&nbsp;&nbsp;&nbsp;&nbsp;}<br/>14<br/>15}<br/>16</div></div><br/><br/>运行一下.你就会发现,每个方法之后没有记录日志了. 这样,我们就把代理者和操作者解藕了!<br/><br/>下面留一个问题给大家,如果我们不想让所有方法都被日志记录,我们应该怎么去解藕呢.?<br/>我的想法是在代理对象的public Object invoke(Object proxy, Method method, Object[] args)方法里面加上个if(),对传进来的method的名字进行判断,判断的条件存在XML里面.这样我们就可以配置文件时行解藕了.如果有兴趣的朋友可以把操作者,被代理者,都通过配置文件进行配置 ,那么就可以写一个简单的SpringAOP框架了.<br/><br/> ]]></description>
		</item>
		
			<item>
			<link>http://www.javamilk.org/article.asp?id=549</link>
			<title><![CDATA[关于产生Connection reset by peer: socket write error错误原因]]></title>
			<author>blurxx@yahoo.cn(Java伴侣)</author>
			<category><![CDATA[EJB&amp;Spring]]></category>
			<pubDate>Thu,21 Feb 2008 11:10:37 +0800</pubDate>
			<guid>http://www.javamilk.org/default.asp?id=549</guid>
		<description><![CDATA[web端与ejb通信的数据包(数据对象)大小受weblogic容器的限制,默认为10M最大为2G.]]></description>
		</item>
		
			<item>
			<link>http://www.javamilk.org/article.asp?id=362</link>
			<title><![CDATA[NoSuchMethodError: o&#114;g.springframework.beans.prope]]></title>
			<author>blurxx@yahoo.cn(Java伴侣)</author>
			<category><![CDATA[EJB&amp;Spring]]></category>
			<pubDate>Sat,20 Oct 2007 15:16:24 +0800</pubDate>
			<guid>http://www.javamilk.org/default.asp?id=362</guid>
		<description><![CDATA[java.lang.NoSuchMethodError: o&#114;g.springframework.beans.propertyeditors.ClassEditor<br/><br/>错误原因：spring-beans.jar；spring-core.jar；spring-context.jar版本问题<br/>解决办法：俺的电脑－高级－环境变量－classpath，加入spring2.0 jar]]></description>
		</item>
		
			<item>
			<link>http://www.javamilk.org/article.asp?id=191</link>
			<title><![CDATA[EJB概述]]></title>
			<author>blurxx@yahoo.cn(Java伴侣)</author>
			<category><![CDATA[EJB&amp;Spring]]></category>
			<pubDate>Tue,03 Jul 2007 11:24:58 +0800</pubDate>
			<guid>http://www.javamilk.org/default.asp?id=191</guid>
		<description><![CDATA[Java EE 是一套商业应用系统模型或者说是一种规范。<br/><br/>EJB分为实体Bean（数据库操作）、会话Bean（逻辑操作）、消息驱动Bean。<br/>会话Bean操作实体Bean]]></description>
		</item>
		
			<item>
			<link>http://www.javamilk.org/article.asp?id=79</link>
			<title><![CDATA[EJB，在client中的固定四行代码]]></title>
			<author>blurxx@yahoo.cn(Java伴侣)</author>
			<category><![CDATA[EJB&amp;Spring]]></category>
			<pubDate>Wed,18 Oct 2006 13:47:45 +0800</pubDate>
			<guid>http://www.javamilk.org/default.asp?id=79</guid>
		<description><![CDATA[<div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code13788);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.javamilk.org/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code13788><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Context context = client.getInitialContext();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object ref=context.lookup(&#34;FirstEJB&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FirstEJBHome home=(FirstEJBHome)ref;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FirstEJB firstejb=home.cr&#101;ate(); <br/></div></div>]]></description>
		</item>
		
</channel>
</rss>
