dedecms织梦内容管理系统    
首页 | java | C/C++ | PHP | 操作系统 | ajax | 脚本编程 | 安全技术 | 本站下载页 | flex | CRM | 专题 | QQ群 | 测试中心 | 会员中心 | 积分规则
  当前位置:主页>java>开源框架>文章内容
利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析
来源: 作者:
AOP:Aspect Oriented Programming,意为面向切面/局部的程序设计。它是面向对象的程序设计的一种延伸。

本文试图通过使用Java本身的动态属性,来实现一个具有简单的AOP功能的容器。

开始理解起来可能比较费劲,但我们可以通过一个通俗说明来这样理解AOP的概念,就是使用AOP可以不用修改原有的代码,而可以追加新的功能。

比如,我们用AOP实现了用户登陆(判断ID与密码是否正确)功能,现在我们要求在用户登陆时用LOG记录用户登陆的情况。一般的做法是直接修改已有的登陆逻辑代码,但使用AOP,可以不用修改原有的代码而完成此功能。


本文试图通过使用Java本身的动态代理功能,来实现一个具有简单的AOP功能的容器。从而帮助大家对AOP有个大概的认识。

Java动态代理功能
首先,我们简单介绍一下Java动态代理功能。JAVA的动态代理功能主要通过java.lang.reflect.Proxy类与java.lang.reflect.InvocationHandler接口完成,这里正是通过它们实现一个简单的AOP容器的。其实,像JBoss AOP等其他动态AOP框架也都是通过Proxy和InvocationHandler来实现的。


  • Java从JDK1.3开始提供动态代理(Java Proxy)功能。
  • 所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联。
  • AOP(Aspect Oriented Programming):面向切面编程,其中的一种实现方法便是用Proxy来实现的。
  • Java Proxy只能代理接口,不能代理类。
  • Java Proxy功能主要通过java.lang.reflect.Proxy类与java.lang.reflect.InvocationHandler接口实现。
  • java.lang.reflect.Proxy (代理类) > ProxyInterface(被代理的接口)  > InvocationHandler(关联类)> Class(可以在InvocationHandler中被调用)。它们之间的关系可以用下面的流程图来表示:


动态代理类:Proxy  被代理的接口  InvocationHandler实现类  代理类

     实际上的调用关系可以用下面的流程图来表示:

Proxy.newProxyInstance

XxxxInterface xx = $ProxyN(N=0,1,2…)

XxxxInterface.calledMethod

$ProxyN.calledMethod

InvocationHandler.invoke

method.invoke(obj, args)

obj.calledMethod

  1. Proxy. newProxyInstance的参数:必须传送以下3个参数给Proxy. newProxyInstance方法:ClassLoader,Class[],InvocationHandler。其中参数2为被代理的接口 Class,参数3为实现InvocationHandler接口的实例。
  2. 可以通过Proxy. newProxyInstance方法得到被代理的接口的一个实例(instance),该实例由newProxyInstance方法动态生成,并实现了该接口。
  3. 当程序显示调用接口的方法时,其时是调用该实例的方法,此方法又会调用与该实例相关联InvocationHandler的invoke方法。
  4. 这样我们可以在InvocationHandler.invoke方法里调用某些处理逻辑或真正的逻辑处理实现类。



用Java Proxy实现AOP容器
下面我们使用Java Proxy来实现一个简单的AOP容器。
文件列表:
文件名 说明
AopInvocationHandlerImpl.java 该类实现了java.lang.reflect.InvocationHandler接口,我们通过它记录LOG信息
AopContainer.java 简单的AOP容器,通过它把IDoBusiness与AopInvocationHandlerImpl关联起来
IDoBusiness.java 逻辑处理接口
DoBusiness.java 逻辑处理实现类
TestAop.java 测试类

简单的AOP容器:
AopContainer.java
package com.test.aop.framework;

import java.lang.reflect.Proxy;

/**
* A Simple AOP Container
*
*/

public class AopContainer {
    public static <T> T getBean(Class<T> interfaceClazz, final T obj) {
        assert interfaceClazz.isInterface();
        
        return (T) Proxy.newProxyInstance(interfaceClazz.getClassLoader(),
                new Class[] { interfaceClazz }, new AopInvocationHandlerImpl(obj));
    }

    public static Object getBean(final Object obj) {
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(), new AopInvocationHandlerImpl(obj));
    }
}
第一个getBean方法通过2个参数(第一个参数为被代理的接口,第二个参数为被代理的类实例)
第二个getBean方法只有一个参数,就是类的实例。该类必须实现1个以上的接口。本文的例子并没有使用到该方法,所以这里顺便介绍一下它的使用方法。比如有一个类HelloWorld实现了接口IHelloWorld1和IHelloWorld2,那么可以通过
HelloWorld helloWorld = new HelloWorld();
IHelloWorld1 helloWorld1 = (IHelloWorld1)AopContainer.getBean(helloWorld);
//或
IHelloWorld2 helloWorld2 = (IHelloWorld2)AopContainer.getBean(helloWorld);
调用。当然很多时候都不会直接用new HelloWorld()生成HelloWorld实例,这里为了简便,就直接用new生成HelloWorld实例了。

实现InvocationHandler接口的中间类:
AopInvocationHandlerImpl.java
package com.test.aop.framework;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class AopInvocationHandlerImpl implements InvocationHandler {
    private Object bizPojo;
    
    public AopInvocationHandlerImpl(Object bizPojo) {
        this.bizPojo = bizPojo;
    }

    /*
     * (non - Javadoc)
     *
     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
     *      java.lang.reflect.Method, java.lang.Object[])
     */

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object o = null;
        try {
            System.out.println("Start:" + method.getName());
            o = method.invoke(bizPojo, args);
            System.out.println("End:" + method.getName());
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Exception Occured!" + e.getMessage());
            // excetpion handling.
        }
        return o;
    }
}
AopInvocationHandlerImpl.invoke方法的第一个参数为代理类,在我们这个例子里为java.lang.reflect.Proxy类的一个实例。第二个参数Method,为被代理的接口的方法调用(实际上是自动生成代理类的方法调用),第三个方法为方法调用的参数。
我们通过在AopInvocationHandlerImpl.invoke方法里的method.invoke(bizPojo, args)来调用bizPojo类的与被代理接口的同名方法。这里,bizPojo必须实现了被代理的接口。
在我们的例子里,我们在实际上被调用的业务逻辑方法的前后输出了日志信息。

实际上的逻辑处理类。该类实现了被代理的接口:IDoBusiness。
DoBusiness.java
package com.test.aop.framework;

/**
* A business class
*
*/

public class DoBusiness implements IDoBusiness {
    public void printNothing() {
        System.out.println("Just Say Hello!");
    }
    
    public void throwException() {
        throw new RuntimeException("throw Exception from DoBusiness.throwException()");
    }

}

被代理的接口定义:
IDoBusiness.java
package com.test.aop.framework;

/**
* interface for business logic process
*
*/

public interface IDoBusiness {
    public void printNothing();
    public void throwException();
}

测试类:
TestAop.java
package com.test.aop.framework;


/**
* Test AOP
*
*/

public class TestAop {

    /**
     * @param args
     */

    public static void main(String[] args) {
        DoBusiness doBusiness = new DoBusiness();
        IDoBusiness idoBusiness = AopContainer.getBean(IDoBusiness.class, doBusiness);
        idoBusiness.printNothing();
        
        idoBusiness.throwException();
    }

}

总结:
本文通过Java Proxy实现了一个简单地AOP容器。也简单地展示了AOP的基本实现原理,实际上可以以此为基础实现一个功能完善的AOP容器。

上一篇:利用Jakarta Commons组件beanutils、dbutils简化JDBC数据库操作   下一篇:翻译 commons dbutils例子example中文官方文档
[收藏] [推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
用户名: 新注册) 密码: 匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论
  热点文章
·关于JSF和Struts的讨论
·Struts教程-Struts模块化编程教
·Struts入门经验
·用科学的思维方法指导软件的设计
·Hibernate配置文件中映射元素详
·Spring中事件处理的小技巧
·struts2.0pring2.0 hibernate3.2
·struts2.0 spring2.0 hibernate3
·浅谈hibernate lazy fetch
·Hibernate的Fetch
·优化hibernate性能的几点建议
·Hibernate中的取策略延迟加载
  相关文章
·利用Jakarta Commons组件beanuti
·翻译 commons dbutils例子exampl
·Common Dbutils组件的使用
·Common Dbutils组件用法详解(含
·Apache DBUtils实践
·使用 Spring 2.5 TestContext 测
·Spring 2.5架构图
·Spring 2.5 标注开发的简单例子
·JBPM工作流引擎内核设计思想及构
·JBPM工作流引擎内核设计思想及构
·JBPM工作流引擎内核设计思想及构
·JBPM工作流引擎内核设计思想及构
  相关信息
copy right @ 百家拳软件项目研究室 2007 辽ICP备07011763