AOP技术应用和研究--动态代理
2014-09-17 20:44
295 查看
在SpringAop的实现中,我们首先需要知道的就是动态代理。
cglib包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。其原理是Enhancer类通过字节码技术为原有的类创建子类,并且设置好callback到proxy,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。则原有类的每个方法调用都会转为调用实现了MethodInterceptor接口的proxy的intercept()函数。
下面我们来看看了解下jdk动态代理的原理,动态代理还要从 jdk本身说起。在 jdk 的 java.lang.reflect 包下有个 Proxy 类,它正是构造代理类的入口。这个类的结构如下图3.4:
从上图发现最后面四个是公有方法。而最后一个方法 newProxyInstance 就是创建代理对象的方法。这个方法的源码如下:
这个方法需要三个参数:ClassLoader,用于加载代理类的Loader 类,通常这个 Loader 和被代理的类是同一个Loader 类。Interfaces,是要被代理的那些那些接口。InvocationHandler,就是用于执行除了被代理接口中方法之外的用户自定义的操作,他也是用户需要代理的最终目的。用户调用目标方法都被代理到 InvocationHandler 类中定义的唯一方法 invoke 中。这在后面再详解。
首先getProxyClass()方法生成代理类的Class,然后代理类的Class使用getConstructor()方法生成代理类的构造函数,也就是$Proxy4(InvocationHandlerh) 如图3.5 Proxy,
最后cons.newInstance(newObject[]{h})生成代理类的实例并把UserInvocationHandler的实例传给它的构造方法。这就是Proxy生成代理对象的整个过程。下面看看Proxy如何产生代理类的过程,如图3.6,创建代理对象的时序图
getProxyClass()是生成的代理Class。 getProxyClass()方法核心代码如下图3.7:
在getProxyClass()中使用ProxyGenerator类的静态方法generateProxyClass(),这里是真正生成代理类class字节码的地方。最后defineClass0()根据字节码生成代理类实例。
现在,jdk是怎样动态生成代理类的字节的原理已经一目了然了。再来解决另外一个问题,那就是由谁来调用InvocationHandler的invoke方法的。要解决这个问题就要看一下jdk到底为我们生成了一个什么东西。实际上生成的$Proxy4继承了Proxy类和UserDao接口。并且有一个数据成员InvocationHandler如图3.5。$Proxy的构造函数如下:
代理对象就是用上面的构造函数生成的。其中Proxy当然也生成了saveUser(User user)方法。这个方法实际上调用的就是UserInvocationHandler的invoke()方法。这样我们就把jdk和cglib动态代理的思想原理大致的描述完。
代码在:https://github.com/demiaowu/aop
jdk的示例代码代码在:src/cn/miao/proxy/jdk目录下面
cglib的示例代码在:src/cn/miao/proxy/cglib目录下面
AOP技术应用和研究系列博客
AOP技术应用和研究
1,cglib动态代理
先看一个简单的cglib动态代理实例,我们假设的场景是在web开发中,用户实体访问数据库的Dao层UserDao实现事务处理这项功能。具体代码如下:package cn.miao.proxy.cglib; public class User { private String username; private String password; public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
package cn.miao.proxy.cglib; /** * 事务处理类 * @author demiaowu * */ public class Transaction { public void beginTransaction() { System.out.println("begin transaction"); } public void commit() { System.out.println("commit"); } }
package cn.miao.proxy.cglib; import org.junit.Test; /** * cglib动态代理示例测试客户端 * @author demiaowu * */ public class UserClient { @Test public void clientTest() { User user = new User("demiaowu","123456"); //实例化transaction Transaction transaction = new Transaction(); UserDaoImpl target = new UserDaoImpl(); UserMethodInterceptor inteceptor = new UserMethodInterceptor(transaction, target); UserDaoImpl proxy = (UserDaoImpl) inteceptor.getProxy(); proxy.saveUser(user); } }
package cn.miao.proxy.cglib; public class UserDaoImpl{ public void saveUser(User user) { System.out.println("saveUser"); } public void updateUser(User user) { System.out.println("updateUser"); } public void deleteUser(String username) { System.out.println("deleteUser"); } }
package cn.miao.proxy.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class UserMethodInterceptor implements MethodInterceptor { private Transaction transaction; private Object target; public UserMethodInterceptor(Transaction transaction, Object target) { this.transaction = transaction; this.target = target; } public Object getProxy() { Enhancer enhancer = new Enhancer(); //设置需要创建子类的类 enhancer.setSuperclass(this.target.getClass()); enhancer.setCallback(this); //通过字节码技术动态创建子类实例 return enhancer.create(); } public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy proxy) throws Throwable { Object retValue; String methodName = method.getName(); if ("saveUser".equals(methodName) || "updateUser".equals(methodName) || "deleteUser".equals(methodName)) { this.transaction.beginTransaction(); retValue = method.invoke(this.target, arg2); this.transaction.commit(); } else { retValue = method.invoke(this.target, arg2); } return retValue; } }写的jdk实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,就需要cglib了。cglib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用。
cglib包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。其原理是Enhancer类通过字节码技术为原有的类创建子类,并且设置好callback到proxy,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。则原有类的每个方法调用都会转为调用实现了MethodInterceptor接口的proxy的intercept()函数。
2,jdk动态代理
直接看例子吧。package cn.miao.proxy.jdk; /** * 事务处理类 * @author demiaowu * */ public class Transaction { public void beginTransaction() { System.out.println("begin transaction"); } public void commit() { System.out.println("commit"); } }
package cn.miao.proxy.jdk; /** * 用户类 * @author demiaowu * */ public class User { private String username; private String password; public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
package cn.miao.proxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import org.junit.Test; /** * 客户端测试类 * @author demiaowu * */ public class UserClient { @Test public void clientTest() { User user = new User("demiaowu","123456"); //实例化transaction Transaction transaction = new Transaction(); //实例化目标对象 UserDao target = new UserDaoImpl(); //实例化InvocationHandler InvocationHandler userHandler = (InvocationHandler) new UserInvocationHandler(transaction, target); //生成代理对象 UserDao proxy = (UserDao)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), userHandler); proxy.saveUser(user); } }
package cn.miao.proxy.jdk; public interface UserDao { public void saveUser(User user); public void updateUser(User user); public void deleteUser(String username); }
package cn.miao.proxy.jdk; public class UserDaoImpl implements UserDao { public void saveUser(User user) { System.out.println("saveUser"); } public void updateUser(User user) { System.out.println("updateUser"); } public void deleteUser(String username) { System.out.println("deleteUser"); } }
package cn.miao.proxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * User条用处理类 * @author demiaowu * */ public class UserInvocationHandler implements InvocationHandler { private Transaction transaction; private Object target; public UserInvocationHandler(Transaction transaction, Object target) { this.transaction = transaction; this.target = target; } /** * proxy 是Proxy类要为你生成的代理类实例 * method 条用的方法是Method的实例,如果调用saveUser()方法,那么就是saveUser()的Method实例 * args 调用方法传入的参数,如果调用saveUser(User user)方法,那么就是传入的参数user * return 使用代理后将作为调用方法后的返回值,如果调用saveUser(User user)方法,那么就是它的返回值 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object retValue = null; String mehodName = method.getName(); if ("saveUser".equals(mehodName) || "deleteUser".equals(mehodName) || "updateUser".equals(mehodName)) { this.transaction.beginTransaction(); retValue = method.invoke(this.target, args); this.transaction.commit(); } else { retValue = method.invoke(this.target, args); } return retValue; } }
下面我们来看看了解下jdk动态代理的原理,动态代理还要从 jdk本身说起。在 jdk 的 java.lang.reflect 包下有个 Proxy 类,它正是构造代理类的入口。这个类的结构如下图3.4:
从上图发现最后面四个是公有方法。而最后一个方法 newProxyInstance 就是创建代理对象的方法。这个方法的源码如下:
/** * loader:类加载器 * interfaces:目标对象实现的接口 * h:InvocationHandler的实现类 */ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { …//省略 Class cl = getProxyClass(loader, interfaces); try { // 生成代理对象的构造方法(也就是$Proxy4(InvocationHandler h)) Constructor cons = cl.getConstructor(constructorParams); // 生成代理类的实例并把UserInvocationHandler的实例传给它的构造方法 return (Object) cons.newInstance(new Object[] { h }); } …//省略 }
这个方法需要三个参数:ClassLoader,用于加载代理类的Loader 类,通常这个 Loader 和被代理的类是同一个Loader 类。Interfaces,是要被代理的那些那些接口。InvocationHandler,就是用于执行除了被代理接口中方法之外的用户自定义的操作,他也是用户需要代理的最终目的。用户调用目标方法都被代理到 InvocationHandler 类中定义的唯一方法 invoke 中。这在后面再详解。
首先getProxyClass()方法生成代理类的Class,然后代理类的Class使用getConstructor()方法生成代理类的构造函数,也就是$Proxy4(InvocationHandlerh) 如图3.5 Proxy,
最后cons.newInstance(newObject[]{h})生成代理类的实例并把UserInvocationHandler的实例传给它的构造方法。这就是Proxy生成代理对象的整个过程。下面看看Proxy如何产生代理类的过程,如图3.6,创建代理对象的时序图
getProxyClass()是生成的代理Class。 getProxyClass()方法核心代码如下图3.7:
在getProxyClass()中使用ProxyGenerator类的静态方法generateProxyClass(),这里是真正生成代理类class字节码的地方。最后defineClass0()根据字节码生成代理类实例。
现在,jdk是怎样动态生成代理类的字节的原理已经一目了然了。再来解决另外一个问题,那就是由谁来调用InvocationHandler的invoke方法的。要解决这个问题就要看一下jdk到底为我们生成了一个什么东西。实际上生成的$Proxy4继承了Proxy类和UserDao接口。并且有一个数据成员InvocationHandler如图3.5。$Proxy的构造函数如下:
public$Proxy4(InvocationHandler invocationhandler) { super(invocationhandler); }
代理对象就是用上面的构造函数生成的。其中Proxy当然也生成了saveUser(User user)方法。这个方法实际上调用的就是UserInvocationHandler的invoke()方法。这样我们就把jdk和cglib动态代理的思想原理大致的描述完。
代码在:https://github.com/demiaowu/aop
jdk的示例代码代码在:src/cn/miao/proxy/jdk目录下面
cglib的示例代码在:src/cn/miao/proxy/cglib目录下面
AOP技术应用和研究系列博客
AOP技术应用和研究
相关文章推荐
- (尚硅谷)21 反射的应用-动态代理-AOP代理的实现
- JAVA AOP编程之动态代理技术
- AOP技术应用和研究--SpringAop实现原理
- 使用Java动态代理技术实现AOP
- Spring AOP的底层实现技术---JDK动态代理
- 使用Proxy反射类实现AOP动态代理技术
- Spring3核心技术之AOP动态代理
- AOP技术应用和研究--OOP
- AOP技术应用和研究--AOP简单应用
- JAVA AOP编程之动态代理技术
- Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架
- 黑马程序员: 基础加强(反射、类加载器、动态代理技术、AOP、InvocationHandler)
- AOP技术应用和研究--OOP
- Spring AOP的底层实现技术---JDK动态代理
- JAVA AOP编程之动态代理技术
- Aop应用原理 JDK动态代理、代理模式与反射
- Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架
- Spring AOP的底层实现技术---JDK动态代理
- Spring(十)通过动态代理(JDK的Proxy)和cglib实现AOP技术
- AOP技术应用和研究