本文对Spring框架中所包含的AOP思想以及事务管理进行了分析,并通过对一个业务对象实现加锁/解锁的操作,说明了动态代理模式的可行性与有效性。
AD:
我们先来分析一下Spring事务管理机制的实现原理。由于Spring内置AOP默认使用动态代理模式实现,我们就先来分析一下动态代理模式的实现方法。动态代理模式的核心就在于代码中不出现与具体应用层相关联的接口或者类引用,如上所说,这个代理类适用于任何接口的实现。下面我们来看一个例子。
public class TxHandler implements InvocationHandler {
private Object originalObject;
public Object bind(Object obj) {
this.originalObject = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);
} public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
if (!method.getName().startsWith("save")) {
UserTransaction tx = null;
try {
tx = (UserTransaction) (new InitialContext().lookup("java/tx"));
result = method.invoke(originalObject, args);
tx.commit();
} catch (Exception ex) {
if (null != tx) {
try {
tx.rollback();
} catch (Exception e) {
}
}
}
} else {
result = method.invoke(originalObject, args);
}
return result;
}
} |
下面我们来分析一下上述代码的关键所在。
首先来看一下这段代码:
return Proxy.newProxyInstance(
obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this); |
java.lang.reflect.Proxy.newProxyInstance方法根据传入的接口类型(obj.getClass.getInterfaces())动态构造一个代理类实例返回,这也说明了为什么动态代理实现要求其所代理的对象一定要实现一个接口。这个代理类实例在内存中是动态构造的,它实现了传入的接口列表中所包含的所有接口。
再来分析以下代码:
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
……
result = method.invoke(originalObject, args);
……
return result;
} |
InvocationHandler.invoke方法将在被代理类的方法被调用之前触发。通过这个方法,我们可以在被代理类方法调用的前后进行一些处理,如代码中所示,InvocationHandler.invoke方法的参数中传递了当前被调用的方法(Method),以及被调用方法的参数。同时,可以通过method.invoke方法调用被代理类的原始方法实现。这样就可以在被代理类的方法调用前后写入任何想要进行的操作。
Spring的事务管理机制实现的原理,就是通过这样一个动态代理对所有需要事务管理的Bean进行加载,并根据配置在invoke方法中对当前调用的方法名进行判定,并在method.invoke方法前后为其加上合适的事务管理代码,这样就实现了Spring式的事务管理。Spring中的AOP实现更为复杂和灵活,不过基本原理是一致的。
3.AOP思想与动态代理模式的应用实例
综上我们分析了Spring框架的事务管理机制的基本现实原理。尽管Spring框架集中体现了当前流行框架中未曾关注到的一些内容,但是,Spring框架存在晦涩难懂的致命问题。以上通过对Spring框架的一些基本实现原理的研究,给我们带来了一些启示。我们如果不直接使用庞大的Spring框架,而是将融入Spring框架中的AOP思想直接应用于程序中,既绕过了Spring框架这个高门槛,又利用了Spring框架中先进的设计理念,这样便达到了一举两得的目的。
下面我们来看一段代码,我们来编写一个Dynamic Proxy based AOP实现的实例。假设现在有一个UserDao接口和以及其实现类UserDaoImp。
UserDAO.java:
public interface UserDAO {
public void saveUser(User user);
} UserDAOImp.java: public class UserDAOImp implements UserDAO{
public void saveUser(User user) {
……
}
} |
我们需要在saveUser方法中添加对一个业务对象的锁,比如在saveUser前后加锁和解锁。在不影响外部逻辑和不对现有的代码做任何改动的前提下,代理模式是一个不错的选择。但是如果有多个类似的接口,面对每个接口都要实现一个类似的Proxy,实在是一个烦琐无味的苦力过程。回想一下Spring在处理这个问题上的设计理念我们不难想到,使用动态代理模式,是这个问题的一个聪明的解决方法。
public class AOPHandler implements InvocationHandler {
private static Log logger = LogFactory.getLog(AOPHandler.class);
private List interceptors = null;
private Object originalObject;
public Object bind(Object obj) {
this.originalObject = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces().this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{Object result=null
if(method.getName.startsWith(“saveUser”)){
lock();
result=method.invoke(this.originalObject,args);
unlock();
}
return result;
}
private void lock(){
logger.info(“lock object!”);
}
private void unlock(){
logger.info(“unlock object!”);
}
} |
上述代码中并没有出现与具体应用层相关联的接口以及类的引用,所以对所有的类都适用。这就解决了用静态Proxy类实现所产生的弊端。
总结与展望
以上我们讨论了Spring框架基于动态AOP机制实现以及动态代理机制的应用,围绕着AOP的实现与应用,一直有一个热门的话题,即权限管理。Spring框架目前对AOP的支持做得相当出色,但是一直有一个尴尬的问题尚未解决,那就是目前还没有一个完备的权限管理组件。仔细想想,这并不是AOP的瓶颈,而是因为权限管理的形式过于灵活和复杂多变,系统中的权限管理逻辑多种多样各不相同,我们很难做出一个统一的管理与操作。另一方面,权限管理作为一个独立的切面显得过于庞大,需要进一步切分设计,设计过程复杂,实现难度较大。所以我们还在期待着AOP思想在权限管理方面能有突破性的应用与扩展。