您的位置:首页 > 编程语言 > Java开发

Java程序员从笨鸟到菜鸟之(七十三)细谈Spring(五)spring之AOP底层大揭秘

2012-06-10 16:19 423 查看
众所周知,java是面向对象语言的有力代表,提到java我们就会立即想到面向对象,提到面向对象我们就会想到java。然而面向对象也并非完美无缺的,它更注重于对象层次结构方面的东西,对于如何更好的管理对象行为内部结构,还存在着些许不足。那么我们如何使这个问题的得到更完美的解决呢?答案就是AOP。
AOP:Aspect-Oriented Programming。AOP是OOP的补充,是GOF的延续。我们知道设计模式是对于面向对象设计中经验的总结,它孜孜不断追求的就是调用者与被调用者之间的解耦。有了设计模式我们可以更有效的利用面向对象的特性,使得整个软件设计更加灵活、优雅。但是设计模式是基于面向对象的思想而形成的,更多的时候关注的是对象层次的东西,在解决对象行为内部问题方面却有些不足。AOP的出现恰恰就是对面向对象思想做出了完美的补充。

说到AOP,我们就不得不来提一下软件的纵向和横向问题。从纵向结构来看就是我们软件系统的各个模块,它主要负责处理我们的核心业务(例如商品订购、购物车查看);而从横向结构来看,我们几乎每个系统又包含一些公共模块(例如权限、日志模块等)。这些公共模块分布于我们各个核心业务之中(例如订购和查看商品明细的过程都需要检查用户权限、记录系统日志等)。这样一来不仅在开发过程中要处处关注公共模块的处理而且开发后维护起来也是十分麻烦。而有了AOP之后将应用程序中的商业逻辑同对其提供支持的通用服务进行分离,使得开发人员可以更多的关注核心业务开发。



下面我们就以一个简单的例子来看一下AOP吧!比如说,我们现在要开发的一个应用里面有很多的业务方法,但是,我们现在要对这个方法的执行做全面监控,或部分监控.也许我们就会在要一些方法前去加上一条日志记录,我们写个例子看看我们最简单的解决方案
我们先写一个接口IHello.java代码如下:
public interface IHello{  /** *//**   * 假设这是一个业务方法  *@param name  */  void sayHello(String name);  }


里面有个方法,用于输入"Hello" 加传进来的姓名;我们去写个类实现IHello接口

public class Helloimplements IHello{  public void sayHello(String name){ System.out.println("Hello" + name); } }


现在我们要为这个业务方法加上日志记录的业务,我们在不改变原代码的情况下,我们会去怎么做呢?也许,你会去写一个类去实现IHello接口,并依赖Hello这个类.代码如下:
public class HelloProxyimplements IHello{  private IHello hello;    public HelloProxy(IHello hello){  this.hello= hello;   }   public void sayHello(String name){  Logger.logging(Level.DEBUGE,"sayHello method start.");  hello.sayHello(name);  Logger.logging(Level.INFO,"sayHello method end!");   } }


从上面的代码我们可以看出,hello对象是被HelloProxy这个所谓的代理态所创建的.这样,如果我们以后要把日志记录的功能去掉.那我们只要把得到hello对象的的具体实现改为Hello的就可以。上面的代码 就是对AOP的最简单的视线,但是我们接下来想,如果我们要在很多业务逻辑之前加日志的话,那么,我们是不是要去写很多个HelloProxy这样的类呢.没错,是的.其实也是一种很麻烦的事.在jdk1.3以后.jdk跟我们提供了一个API java.lang.reflect.InvocationHandler的类. 这个类可以让我们在JVM调用某个类的方法时动态的为些方法做些什么事.让我们把以上的代码改一下来看看效果.

同样,我们写一个IHello的接口和一个Hello的实现类.在接口中.我们定义两个方法;代码如下 :

IHello.java
package sinosoft.dj.aop.proxyaop;    public interface IHello{  /** *//**   * 业务处理A方法   *@param name  */  void sayHello(String name);  /** *//**  * 业务处理B方法  *@param name */ void sayGoogBye(String name); }


Hello.java

package sinosoft.dj.aop.proxyaop;    public class Helloimplements IHello{    public void sayHello(String name){   System.out.println("Hello" + name);   }  public void sayGoogBye(String name){  System.out.println(name+" GoodBye!");  } }


我们一样的去写一个代理类.只不过.让这个类去实现java.lang.reflect.InvocationHandler接口,代码如下:
package sinosoft.dj.aop.proxyaop;    import java.lang.reflect.InvocationHandler;  import java.lang.reflect.Method; import java.lang.reflect.Proxy;    public class DynaProxyHelloimplements InvocationHandler{    /** *//**  * 要处理的对象(也就是我们要在方法的前后加上业务逻辑的对象,如例子中的Hello) */ private Object delegate;  /** *//**  * 动态生成方法被处理过后的对象 (写法固定)  *  *@param delegate  *@param proxy  *@return */ public Object bind(Object delegate){ this.delegate= delegate; return Proxy.newProxyInstance( this.delegate.getClass().getClassLoader(),this.delegate  .getClass().getInterfaces(),this);  } /** *//**  * 要处理的对象中的每个方法会被此方法送去JVM调用,也就是说,要处理的对象的方法只能通过此方法调用  * 此方法是动态的,不是手动调用的 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{  Object result= null; try { //执行原来的方法之前记录日志  Logger.logging(Level.DEBUGE, method.getName()+ " Method end .");  //JVM通过这条语句执行原来的方法(反射机制)  result= method.invoke(this.delegate, args); //执行原来的方法之后记录日志  Logger.logging(Level.INFO, method.getName()+ " Method Start!");  } catch (Exception e){  e.printStackTrace();  } //返回方法返回值给调用者  return result; } }


从上面的例子我们看出.只要你是采用面向接口编程,那么,你的任何对象的方法执行之前要加上记录日志的操作都是可以的.他(DynaPoxyHello)自动去代理执行被代理对象(Hello)中的每一个方法,一个java.lang.reflect.InvocationHandler接口就把我们的代理对象和被代理对象解藕了

本文出自 “曹胜欢” 博客,请务必保留此出处http://javacsh.blog.51cto.com/3545281/1129201
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐