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
分享到:
相关推荐
SpringIOC,DI+dynamic proxy 实现盗版AOP的源代码
为了说明Spring的AOP原理,本人使用代理模式中的动态代理完成演示AOP编程的原理的演示。相信,如果你耐心看完整个程序(几乎一行注释一行代码),那么你对Spring这个东西就不是觉得有什么神秘了! 阅读对象:凡是喜爱...
IoC原理分析 基于XML的IoC实现 ... Spring AOP基于XML和注解的实现 Spring应用之Spring JDBC实现 Spring应用之JdbcDaoSupport Spring应用之事务支持 Spring与Mybatis整合
有一天在用回调模版的时候,忽然间又想到jdk自带的Proxy类似乎不是怎么好用,为何不把其做成回调模版呢,可以将其改造称类似spring Aop 代码如下: package com.fjx.proxy.up.test; import ...
Jdk动态代理,基于接口的代理示例 InovactionHandler Proxy
spring之AOP(动态代理),包括jdk动态代理和CGLib动态代理
利用JAVA代理Proxy机制实现spring对ibaits的MapperScannerConfigurer功能 详细:http://blog.csdn.net/wq105032007067/article/details/8812598
Spring 会使用 java.lang.reflect.Proxy 类来创建代理对象。 CGLIB 代理:用于代理没有实现接口的类或final类。CGLIB(Code Generation Library)是一个代码生成的类库,可以在运行时动态生成一个目标类的子类,并...
package com.gc.aop下为:aop方式ProxyFactoryBean代理...package com.gc.javaproxy下为:java代理机制实现 package com.gc.proxy下为:自定义代理模式(面向接口编程) package com.gc.normal下为:通用日志处理方式
package cn.sxt.dynamicproxy; import java.util.ArrayList; import java.util.List; import cn.sxt.service.UserService; import cn.sxt.service.UserServiceImpl; public class Client { public ...
Spring示例_Printer_Spring_AOP_Spring_Proxy
JAVA AOP例子, 包括cglib, jsvassist, dynamicProxy
Spring源代码解析(五):Spring_AOP获取Proxy.doc
Spring初探 准备工作 构建Spring基础代码 Spring 基础语义 Dependency Injection 依赖注入的几种实现类型 ... Dynamic Proxy 与Spring AOP CGLib 与 Spring AOP AOP 应用 DAO Support Remoting
NULL 博文链接:https://cn-done.iteye.com/blog/1743191
spring对AOP的支持 1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK...
我自己用eclipse写的java代码,可以直接用eclipse导入,也可以直接用java -jar proxy_sample.jar执行 代码量很小,尽量通过注释进行说明 本例实现了InvocationHandler接口,代码具有典型性 在研究代理模式(Proxy...
NULL 博文链接:https://mofeichen.iteye.com/blog/444168
Castle AOP 对类方法调用的拦截示例Deom(可运行),有3.1版的Castle.Core.dll
使用JDK中的Proxy技术实现AOP功能与使用CGLIB实现AOP功能