spring中的AOP(代理对象)

在一个服务的流程中插入与业务逻辑无关的系统服务逻辑(如logginng,security),这样的逻辑称为cross-cutting concerns,将cross-cutting concerns独立出来设计为一个对象,这样的特殊对象称为Aspect,Aspect-oriented programming着重在Aspect的设计及与应用程序的织入(Weave)。
spring实现aop的方式之一是代理机制:
例如:当执行某些方法时候需要记录日志:一般这么写:
public class HelloSpeak(){
private logger = Logger.getLogger(this.getClass().getName());
public void sayHello(){
logger.log(Level.Info,"begin");
system.out.println("zzheng zai zhi xing");
logger.log(Level.Info,"end");
}
}
对于HelloSpeaker来说,记录日志的方法不是他的业务逻辑,这么做增加了他额外的职责,如果很多类都这么做,程序会很混乱。特别是还有其他的职能:如事务检查,安全处理,权限检查等。
可以使用代理(Proxy)机制来解决这个问题,在这边讨论两种代理方式:静态代理(Static proxy)与动态代理(Dynamic proxy)。
[b]静态代理[/b]
在静态代理的实现中,代理对象与被代理的对象都必须实现同一个接口,在代理对象中可以实现日志记录等相关服务,并在需要的时候再呼叫被代理的对象,如此代理对象当中就可以仅保留业务相关职责。举个实际的例子来说,首先定义一个IHello接口:
package aop;

public interface Ihello {
public void sayHello();
}
然后让实现业务逻辑的HelloSpeaker类实现IHello接口,例如:
package aop;

public class HelloSpeak implements Ihello {

public void sayHello() {
System.out.println("ni hao.");

}

}
在HelloSpeaker类中现在没有任何记录的程序代码插入其中,日志记录服务的实现将被放至代理对象之中,代理对象同样也要实现IHello接口,例如
public class HelloProxy implements Ihello {

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

public HelloProxy(Ihello hellotest) {
this.hellotest = hellotest;
}

public void sayHello() {
log("begin ************");
hellotest.sayHello();
System.out.println("****" + logger);
log("end **********");
}

private void log(String msg) {
logger.log(Level.INFO, msg);
}
}

测试类如下:
public class Test {

/**
* @param args
*/
public static void main(String[] args) {
HelloSpeak hs = new HelloSpeak();
HelloProxy hp = new HelloProxy(hs);
hp.sayHello();
}

}
代理对象的一个接口只服务于一种类型的对象,而且如果要代理的方法很多,势必要为每个方法进行代理,静态代理在程序规模稍大时就无法胜任。

[b]动态代理[/b]
在JDK1.3之后加入了可协助开发动态代理功能的API,您不必为特定对象与方法编写特定的代理对象,使用动态代理,可以使得一个处理者(Handler)服务于各个对象。首先,一个处理者的类设计必须实现java.lang.reflect.InvocationHandler接口,以实例来进行说明,例如设计一个LogHandler类
package dynamic;

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 LogHandler implements InvocationHandler {
private Logger log = Logger.getLogger(this.getClass().getName());

private Object delegate;
public Object bind(Object delegate){
this.delegate = delegate;
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
this.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
try{
log("begin *********"+method);
result = method.invoke(delegate, args);
log("end *****"+method);
}catch(Exception e){
log(e.toString());
}

return result;
}
private void log(String msg){
log.log(Level.INFO,msg);
}

}
主要的概念是使用Proxy .newProxyInstance ()静态方法建立一个代理对象,建立代理对象时必须告知所要代理的接口,之后您可以操作所建立的代理对象,在每次操作时会执行InvocationHandler的invoke()方法,invoke ()方法会传入被代理对象的方法名称与执行参数,实际上要执行的方法交由method.invoke(),您在method.invoke()前后加上记录动作,method.invoke ()传回的对象是实际方法执行过后的回传结果。要实现动态代理,同样必须定义所要代理的接口,例如
package dynamic;

public interface Ihello {
public void sayHello();
}
然后让实现业务逻辑的HelloSpeaker类实现IHello接口,例如:
public class HelloSpeak implements Ihello {

public void sayHello() {
System.out.println("ni hao.");

}

}
编写一个测试的程序,您要使用LogHandler的bind ()方法来绑定被代理对象,如下所示:
public class Test {

/**
* @param args
*/
public static void main(String[] args) {
LogHandler lh = new LogHandler();
HelloSpeak ee = new HelloSpeak();
Ihello tt = (Ihello) lh.bind(ee);
tt.sayHello();
}

}
LogHandler不再服务于特定对象与接口,而HelloSpeaker也不用插入任何有关于记录的动作,它不用意识到记录动作的存在。
以上例子中,HelloSpeake本身的职责是显示招呼文字,却必须插入记录(Log)动作,这使得HelloSpeaker 的职责加重,在 AOP的术语来说,记录的程序代码横切(Cross-cutting)入HelloSpeaker的程序执行流程中,记录这样的动作在AOP中称之为横切关切点 (Cross-cutting concern)。
使用代理对象将记录等与业务逻辑无关的动作或任务提取出来,设计为一个服务对象,像是之前范例中示范的HelloProxy或是LogHandler,这样的对象称之为切面(Aspect)。
AOP中的Aspect所指的可以像是记录等这类的动作或服务,您将这些动作(Cross-cutting concems)设计为通用、不介入特定业务对象的一个职责清楚的Aspect对象,这就是所谓的Aspect-oriented programming,缩写名词即为 AOP 。
在好的设计之下, Aspect可以独立于应用程序之外,在必要的时候,可以介入应用程序之中提供服务,而不需要相关服务的时候,又可以将这些Aspect直接从应用程序中脱离,而应用程序本身不需修改任何一行程式码。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值