基于Java Dynamic Proxy(面向Interface)的Spring AOP实现原理

Dynamic Proxy是面向接口的动态代理实现,其代理对象必须是某个接口的实现。Dynamic Proxy通过在运行期构建一个此接口的动态实现类完成对目标对象的代理(相当于在运行期动态构造一个UserDAOProxy,完成对UserDAOImp的代理任务)。而如果目标代理对象并未实现任何接口,那么Dynamic Proxy就失去了创建动态代理类的基础依据。

我们先来看传统方式下一个Proxy的实现实例。
假设我们有一个UserDAO接口及其实现类UserDAOImp:
UserDAO.java:
public interface UserDAO {
public void saveUser(User user);
}
UserDAOImp.java:
public class UserDAOImp implements UserDAO{
public void saveUser(User user) {
……
}
}

UserDAOImp.saveUser方法中实现了针对User对象的数据库持久逻辑。
如果我们希望在UserDAOImp.saveUser方法执行前后追加一些处理过程,如启动/
提交事务,而不影响外部代码的调用逻辑,那么,增加一个Proxy类是个不错的选择:
UserDAOProxy.java
public class UserDAOProxy implements UserDAO {
private UserDAO userDAO;
public UserDAOProxy(UserDAO userDAO) {
this.userDAO = userDAO;
}
public void saveUser(User user) {
UserTransaction tx = null;
try {
tx = (UserTransaction) (
new InitialContext().lookup("java/tx")
);
userDAO.saveUser(user);
tx.commit();
} catch (Exception ex) {
if (null!=tx){
try {
tx.rollback();
}catch(Exception e) {
}
}
}
}
}

UserDAOProxy同样是UserDAO接口的实现,对于调用者而言,saveUser方法的使用完全相同,不同的是内部实现机制已经发生了一些变化――我们在UserDAOProxy中为UserDAO.saveUser方法套上了一个JTA事务管理的外壳。
上面是静态Proxy模式的一个典型实现。

现在假设系统中有20个类似的接口,针对每个接口实现一个Proxy,实在是个繁琐无味的苦力工程。
Dynamic Proxy的出现,为这个问题提供了一个更加聪明的解决方案。
我们来看看怎样通过Dynamic Proxy解决上面的问题:

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;
}
}

首先注意到,上面这段代码中,并没有出现与具体应用层相关的接口或者类引用。也就是说,这个代理类适用于所有接口的实现。
其中的关键在两个部分:
1.
return Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
this);

java.lang.reflect.Proxy.newProxyInstance方法根据传入的接口类型(obj.getClass().getInterfaces())动态构造一个代理类实例返回,这个代理类是JVM在内存中动态构造的动态类,它实现了传入的接口列表中所包含的所有接口。
这里也可以看出,Dynamic Proxy要求所代理的类必须是某个接口的实现(obj.getClass().getInterfaces()不可为空),否则无法为其构造响应的动态类。这也就是为什么Spring对接口实现类通过Dynamic Proxy实现AOP。

2.
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方法调用被代理类的原始方法实现。这样,我们就可以在被代理类的方法调用前后大做文章。
在示例代码中,我们为所有名称以“save”开头的方法追加了JTA事务管理。

谈到这里,可以回忆一下Spring事务配置中的内容:
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>

想必大家已经猜测到Spring事务管理机制的实现原理。
是的,只需通过一个Dynamic Proxy对所有需要事务管理的Bean进行加载,并根据配置,在invoke方法中对当前调用的方法名进行判定,并为其加上合适的事务管理代码,那么就实现了Spring式的事务管理。当然,Spring中的AOP实现更为复杂和灵活,不过基本原理一致。

Spring中Dynamic Proxy AOP实现类为:
org.springframework.aop.framework.JdkDynamicAopProxy
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值