注册本站  论坛  繁體中文

电脑技巧
手机 | MP3 | MP4 | 显卡 | 主板 | 显示器 | 光存储 | 笔记本 | 网络设备 | 移动存储 | 数码相机
键鼠 | CPU | 音箱 | GPS | 电视 | 服务器 | 投影机 | 机箱电源 | 品牌电脑 | 办公打印 |
| 网站首页 | Cisco | Windows | Linux | Java | Dotnet | Oracle | 网页设计 | 平面设计 | 安全 | 软件应用 | 电脑维修 | 办公维修 |
您现在的位置: 电脑技巧 >> Java >> 开源技术 >> Spring >> Java正文

spring AOP面向切面编程

文章来源:中国IT实验室收集整理 作者:佚名 更新时间:2008-6-28 20:35:47 【 】 【加入收藏

      spring里面有个概念叫aop(面向切面编程),很好很强大又很让人费解,很多开发人员会用并且天天挂在嘴边但是不理解其核心原理,今天周末有空,我想用一个小系列的文章给大家把aop分析清楚。要理解aop,首先要掌握java中的代理模式。

    在日常生活中,会遇到各种各样的中介机构,比如猎头公司,律师事务所,婚姻介绍所,房产公司等。在这些单位工作的人员均可称为代理人。代理人的共同特征是可以代替委托人去和第三方通信。譬如:律师代替委托人打官司,猎头代替委托人物色人才,红娘代替委托人寻找对象,房产代理人代替委托人出租房屋。

    代理人可以在第三方和委托人之间转发或过滤消息,但是不能取代委托人的任务。譬如你要找女朋友,委托你一要好的哥们去帮你物色,结果被他给物色了。这就不叫代理。

    代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

    代理模式一般涉及到的角色有:

    抽象角色:声明真实对象和代理对象的共同接口;

    代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

    真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

    我们来看个例子:

    package com.softeem.aop.staticProxy;

    /**

     * @author leno

     *抽象角色

     */

    public interface IHello {

      String greeting(String who);

    }

    package com.softeem.aop.staticProxy;

    /**

     * @author leno

     *真实角色

     */

    public class HelloImpl implements IHello {

     public String greeting(String who) {

                  System.out.println("greeting method is invoked.....");

                  return "hello,"+who;

           }

    }

    试想一下,如果这时候我们要对问候的业务逻辑方法进行日志记录。我们当然可以这样做:

    package com.softeem.aop.staticProxy;

    /**

     * @author leno

     *真实角色

     */

    public class HelloImpl implements IHello {

    private Logger logger = Logger.getLogger(this.getClass().getName());

     public void log(String message)

     {

      logger.log(Level.INFO, message);

     }

     public String greeting(String who) {

          log( "starting...");

           System.out.println("greeting method is invoked.....");

          log("stopping...");

           return "hello,"+who;

     }

    可问题来了,项目经理发话,不容许修改现存的类的实现。怎么办?这时候我们就要就想到代理模式了。我们再加一个代理类:

    静态代理类:

    package com.softeem.aop.staticProxy;

    import java.util.logging.Level;

    import java.util.logging.Logger;

    public class HelloLoggerProxy implements IHello {

     private Logger logger = Logger.getLogger(this.getClass().getName());

     private IHello helloImpl;

     public HelloLoggerProxy(IHello helloImpl) {

      super();

      this.helloImpl = helloImpl;

     }

     public String greeting(String who) {

      log( "starting...");

      String hello = helloImpl.greeting(who);

      log("stopping...");

      return hello;

     }

     public void log(String message)

     {

      logger.log(Level.INFO, message);

     }

    }

    客户端测试代码:

    package com.softeem.aop.staticProxy;

    public class TestStaticProxy {

           public static void main(String[] args) {

                  IHello hello = new HelloLoggerProxy(new HelloImpl());

                  hello.greeting("leno");

           }

    }

     由以上代码可以看出,客户实际需要调用的是HelloImpl类的greeting()方法,现在用HelloLoggerProxy来代理HelloImpl类,同样达到目的,同时还在方法调用的前后都做了日志记录。这就是静态代理。

    但是,如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实色必须对应角一个代理角色,如果大量使用会导致类的急剧膨胀;而且,如果项目中要做日志的类有100个,每个类里面有100个方法。重复代码就太可怕了。有人说,不怕,我就一愚公。好,有天项目经理突然要求修改做日志的方式,你再看看这些方法,估计撞墙的心都有了。那怎么办?我们就改用动态代理。

    JDK1.3以后提供了动态代理的支持,程序员通过实现java.lang.reflect.InvocationHandler接口提供一个执行处理器,然后通过java.lang.reflect.Proxy得到一个代理对象,通过这个代理对象来执行商业方法,在商业方法被调用的同时,执行处理器会被自动调用。

    动态代理类:

    package com.softeem.aop.dynamicProxy;

    import java.lang.reflect.InvocationHandler;

    import java.lang.reflect.Method;

    import java.lang.reflect.Proxy;

    import java.util.logging.Level;

    import java.util.logging.Logger;

    public class DynamicLoggerProxy implements InvocationHandler {

           private Logger logger = Logger.getLogger(this.getClass().getName());

           private Object delegate;

           @SuppressWarnings("unchecked")

 

          public  Object bind(Object delegate)

           {

                  this.delegate = delegate;

                  Class cls = delegate.getClass();

                  return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), this);

           }

           public Object invoke(Object o, Method method, Object[] args)

                         throws Throwable {

                  log( "starting...");

                  Object obj = method.invoke(delegate, args);

                  log("stopping...");

                  return null;

           }

           public void log(String message)

           {

                  logger.log(Level.INFO, message);

           }

    }

    客户端测试代码:

    package com.softeem.aop.dynamicProxy;

    public class TestDynamicProxy {

           public static void main(String[] args) {

                  IHello hello = (IHello) new DynamicLoggerProxy().bind(new HelloImpl());

                  hello.greeting("leno");

           }

    }

    大家看到,一个动态代理类就代替了无数个静态代理类。一劳永逸。这里涉及到一些java反射的知识,我会在以后单独讲述。

    java的动态代理非常实用和强大,可它有一个前提,需要我们的处理业务逻辑的类必须至少实现一个接口,虽然面向接口编程是

    需要提倡的,但如果我们有些现存的类就是没有实现接口,那如何代理呢?这就需要CGLIB的帮助了。继续改进我们的代码:

    没有实现任何接口的类:

    package com.softeem.aop.cglibProxy;

    public class Hello{

           public void greeting(String who) {

                  System.out.println("hello,"+who);

           }

    }

    CGLIB代理类:

    package com.softeem.aop.cglibProxy;

    import java.lang.reflect.Method;

    import java.util.logging.Level;

    import java.util.logging.Logger;

    import net.sf.cglib.proxy.Enhancer;

    import net.sf.cglib.proxy.MethodInterceptor;

    import net.sf.cglib.proxy.MethodProxy;

    public class CGLIBLoggerProxy implements MethodInterceptor {

           private final Logger logger = Logger.getLogger(this.getClass().getName());

           public Object bind(Object delegate)

           {

                  Enhancer enhancer = new Enhancer();

                  enhancer.setCallback(this);

                  enhancer.setSuperclass(delegate.getClass());

                  return enhancer.create();

           }

           public Object intercept(Object o, Method method, Object[] args,

                         MethodProxy proxy) throws Throwable {

                  log( "starting...");

                  proxy.invokeSuper(o, args);

                  log("stopping...");

                  return null;

           }

           public void log(String message)

           {

                  logger.log(Level.INFO,message);

           }

    }

    客户端测试代码:

    package com.softeem.aop.cglibProxy;

    public class TestCGLIBProxy {

           public static void main(String[] args) {

                  Hello hello = (Hello) new CGLIBLoggerProxy().bind(new Hello());

                  hello.greeting("leno");

           }

    }

    好了,有了动态代理和CGLIB,那我们就可以给任何实际的类提供代理了。从而可以在我们的代理类中加入一些与业务逻辑无关的系统级的功能服务,如:日志记录,事务处理,安全管理等。而且不会影响到我们现有的系统。看起来似乎很完美了。但是且慢,如果我们的应用中有些需要这些系统级的功能服务,而有些又不需要呢?如果把代码写死了显然达不到我们的要求。怎么办?这时候就要用到一个非常重要的思想:用配置代替编码。

  • 上一篇Java:

  • 下一篇Java:
  • 最 新 热 门
     手机开发平台指南、教程和资料介绍
     关于什么叫面向接口编程
     编写高级JavaScript应用代码
     不要验证,直接转化科学计数法
     Eclipse插件开发中实现刷新和重编译介绍
     Java开源技术:Eclipse的使用技巧详解
     配置eclipse 3.2 使用JDK1.5中文JavaAPI
     集成Windows本地应用到Eclipse RCP 程序中
     hibernate.cfg.xml配置文件的说明
     eclipse开发jface时,main.class解决方法
    最 新 推 荐
     ibatis+spring 集成
     结合Spring2.0和ActiveMQ进行异步消息调用
     servlet中如何访问spring容器
     Spring MVC与struts比较
     Spring security 命名空间的使用
     spring AOP面向切面编程
     关于String对象解析
     关于Spring切点函数@args()
     Spring中事务的传播属性详解
     Spring+Ibatis+事务处理
    相 关 文 章

    编写高级JavaScript应用代码
    ibatis+spring 集成
    结合Spring2.0和ActiveMQ进行异步消息调用
    servlet中如何访问spring容器
    Spring MVC与struts比较
    Spring security 命名空间的使用
    关于String对象解析
    关于Spring切点函数@args()
    Spring中事务的传播属性详解
    Spring+Ibatis+事务处理

    | 设为首页 | 加入收藏 | 联系站长 | 友情链接 | 版权申明 | 网站公告

     

    Copyright 2006-2008 pcjx.com All Rights Reserved
    电脑技巧 版权所有 粤ICP备06059145号 地图
    本网站所有内容未经许可不得转载或做其他使用