您的位置:首页 > 运维架构

AOP动态代理模式的实现

2013-03-22 12:42 357 查看
Aspect Oriented Programming 面向切面编程:通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。拿一个例子来帮助理解一下。

假如我们现在要开发一个应用,而应用里面有很多业务方法,但是现在我们要对业务方法的执行进行监控。怎么去做?写个例子来看一下。

先写个接口IWork.java,代码如下

public interface IWork
{
/**
*
* doWork(业务方法)
* (这里描述这个方法适用条件 – 可选)
* @return void
* @exception
* @since  1.0.0
*/
public void doWork();
}


doWork方法用来执行我们的主业务,下面写个类实现IWork接口

public class Work implements IWork
{

public void doWork()
{
System.out.println("working");
}

}


现在我们要监控主业务方法的执行,在主业务方法中加上日志记录的操作。

public class Work implements IWork
{

public void doWork()
{
Logger.logging(Sequence.BEFORE);
System.out.println("working");
Logger.logging(Sequence.AFTER);
}
}


Logger类和Sequence枚举类代码如下

Logger.java

public class Logger
{

public static void logging(Sequence seq)
{
if(seq.equals(Sequence.BEFORE))
{
System.out.println("before working");
}
if(seq.equals(Sequence.AFTER))
{
System.out.println("after working");
}
}
}


Sequence.java

public enum Sequence {

BEFORE,AFTER;
}


下面我们写一个测试类,代码如下

public class MainTest
{

public static void main(String[] args)
{
IWork work = new Work();
work.doWork();
}
}


执行结果如下:

before working

working

after working

现在我们发现一个问题,上面的写法已经将日志记录业务和主业务紧密耦合在一块了,这不是AOP的做法,AOP是在不修改源代码的情况下给程序统一添加功能,也许我们要采取另一种做法,写一个类实现IWork类并依赖Work类,代码如下

public class WorkProxy implements IWork
{

private IWork work;
public WorkProxy(IWork work)
{
this.work = work;

}
public void doWork()
{
Logger.logging(Sequence.BEFORE);
work.doWork();
Logger.logging(Sequence.AFTER);
}
}


修改doWork方法,将日志记录去掉,修改MainTest类,代码如下

public class MainTest
{

public static void main(String[] args)
{
IWork work = new WorkProxy(new Work());
work.doWork();
}
}


执行结果如下:

before working

working

after working

从上面的代码可以看出,代理模式其实就是AOP的雏形,doWork方法就是一个切面。通过这种方式实现了辅助业务和主业务方法的解耦。我们不需要调用日志记录的logging方法就完成了日志记录的操作。

但是现在我们又会发现另一个问题,如果我们有多个Work这样的类,我们就需要对应着去写多个代理类,这就需要动态代理模式

jdk1.3以后java提供了java.lang.reflect.InvocationHandler类. 这个类可以让我们在JVM调用某个类的方法时动态的为这些方法做些什么事,把以上的代码改一下。

WorkProxy.java

/**
*
* 类名:WorkProxy
* 类描述: 动态代理类
* 创建人:user
* 修改人:user
* 修改时间:2013-3-22 上午10:20:21
* 修改备注:
* @version 1.0.0
*
*/
public class WorkProxy implements InvocationHandler
{
/**
* 需要代理的类
*/
private Object target;

/**
*
* bind(绑定一个委托对象,并返回一个代理类)
* (写法固定)
* @param target
* @return Object
* @exception
* @since  1.0.0
*/
public Object bind(Object target)
{
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this);
}

/**
*
* invoke(代理对象的的每一个方法会被此方法送去JVM调用,代理对象的方法也只能通过 此方法调用)
* (此方法是动态的,非手动调用的)
* @param proxy 被代理的对象
* @param method 要调用的方法
* @param args 方法调用时需要的参数
* @return Object
* @exception
* @since  1.0.0
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
Object result = null;
/**
* 执行方法 之前记录日志
*/
Logger.logging(Sequence.BEFORE);
result = method.invoke(this.target, args);
/**
* 执行方法之后记录日志
*/
Logger.logging(Sequence.AFTER);
return result;
}
}


修改MainTest类,代码如下:

/**
*
* 类名:MainTest
* 类描述:
* 创建人:user
* 修改人:user
* 修改时间:2013-3-22 上午10:22:04
* 修改备注:
* @version 1.0.0
*
*/
public class MainTest
{

public static void main(String[] args)
{
IWork work = (IWork)new WorkProxy().bind(new Work());
work.doWork();
}
}


执行结果如下:

before working
working
after working

从上面的例子看出.只要是采用面向接口编程,那么,任何对象的方法执行之前要加上日志记录的操作都是可以的.他(WorkProxy)自动去代理执行被代理对象(Work)中的每一个方法,一个

java.lang.reflect.InvocationHandler接口就把我们的代理对象和被代理对象解藕了.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: