Java 动态代理以及Cglib代理
2014-07-27 20:43
218 查看
代理为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式通常也作为AOP(面向切面编程)的底层技术实现。通过AOP可以有效的降低模块间的耦合,也可以进一步补充了OOP。
Java本身提供了Proxy和InvocationHandler实现了动态的代理。
InvocationHandler接口中声明了一个方法:
Proxy,通过该类配合InvocationHandler可以生成目标对象的代理。
代码示例:
首先定义一个接口,Animal:包含吃东西和睡觉两个动作。
然后定义一个Person,实现Animal接口:
Person代理类:
输出:
可以看到,调用代理Person的方法,都会经过InvocationHandler里的invoke方法。
Proxy.newProxyInstance 创建的代理类是class sun.proxy.$Proxy,它具有所有Person的方法,其方法内部则是直接调用InvocationHandler.invoke(xxx)函数。
Cglib动态代理,Java本身提供的动态代理使用也很方便,但有一个缺点,就是被代理的对象必须实现接口。也就是说Java本身的代理不能代理没有实现接口的对象。Cglib是基于ASM字节码操作框架的动态代理生成框架。它可以对没有接口实现的对象进行代理。
Cglib需要使用MethodInterceptor方法拦截器进行,示例代码如下:
AnimalMethodInterceptor 定义一个Animal方法的拦截器:
代理类:
输出:
可以看到Cglib主要以继承的形式进行代理,那么Cglib就相应的无法对final类进行代理了,因为final类无法继承。
源码地址:https://github.com/gavincook/proxy
Java本身提供了Proxy和InvocationHandler实现了动态的代理。
InvocationHandler接口中声明了一个方法:
/** * @param proxy 被代理的对象 * @param method 要调用的方法 * @param args 调用方法所需的参数 * @return * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
Proxy,通过该类配合InvocationHandler可以生成目标对象的代理。
/** * * @param loader 被代理对象的类加载器 * @param interfaces 被代理对象所实现的接口 * @param h 方法调用处理器 * @return * @throws IllegalArgumentException */ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
代码示例:
首先定义一个接口,Animal:包含吃东西和睡觉两个动作。
package org.antstudio; /** * Created by Gavin on 14-7-27. */ public interface Animal { public void eat(); public void sleep(); }
然后定义一个Person,实现Animal接口:
package org.antstudio; /** * @author Gavin * @date 14-7-27 下午2:09 */ public class Person implements Animal{ private String name; public Person(String name){ this.name = name; } public void eat(){ System.out.println(name+" Eating..."); } public void sleep(){ System.out.println(name+" Sleeping..."); } }
Person代理类:
package org.antstudio.proxy; import org.antstudio.Animal; import org.antstudio.Person; import java.io.*; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * @author Gavin * @date 14-7-27 13:45 */ public class SimpleProxy implements InvocationHandler{ private Object target; public Animal getProxy(Animal o){ this.target = o; return (Animal)Proxy.newProxyInstance(o.getClass().getClassLoader(), new Class[]{Animal.class}, this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); System.out.println("Simple Proxy before method:"+methodName); Object result = method.invoke(target,args); //这里如果使用proxy来处理方法的调用会抛出异常,因为proxy方法的调用,会触发拦截器,而拦截器又会触发方法调用,产生死循环 System.out.println("Simple Proxy after method:"+methodName); return result; } public static void main(String[] args) throws IOException { Person person = new Person("Gavin"); Animal proxy = new SimpleProxy().getProxy(person); proxy.eat(); proxy.sleep(); } }
输出:
Simple Proxy before method:eat Gavin Eating... Simple Proxy after method:eat Simple Proxy before method:sleep Gavin Sleeping... Simple Proxy after method:sleep
可以看到,调用代理Person的方法,都会经过InvocationHandler里的invoke方法。
Proxy.newProxyInstance 创建的代理类是class sun.proxy.$Proxy,它具有所有Person的方法,其方法内部则是直接调用InvocationHandler.invoke(xxx)函数。
Cglib动态代理,Java本身提供的动态代理使用也很方便,但有一个缺点,就是被代理的对象必须实现接口。也就是说Java本身的代理不能代理没有实现接口的对象。Cglib是基于ASM字节码操作框架的动态代理生成框架。它可以对没有接口实现的对象进行代理。
Cglib需要使用MethodInterceptor方法拦截器进行,示例代码如下:
AnimalMethodInterceptor 定义一个Animal方法的拦截器:
package org.antstudio.proxy; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * @author Gavin * @date 14-7-27 下午4:43 */ public class AnimalMethodInterceptor implements MethodInterceptor{ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("Cglib proxy before method:"+method.getName()); Object result = methodProxy.invokeSuper(o, objects); //如果这里调用 method.invoke(o,objects)-->会抛出异常,因为调用method时,会触发拦截器,在拦截器里又调用method,会产生死循环 System.out.println("Cglib proxy after method:"+method.getName()); return result; } }
代理类:
package org.antstudio.proxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import org.antstudio.Person; /** * @author Gavin * @date 14-7-27 下午5:05 */ public class CglibProxy { private MethodInterceptor methodInterceptor; public CglibProxy(MethodInterceptor methodInterceptor){ this.methodInterceptor = methodInterceptor; } public <T> T getProxy(T o){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(o.getClass()); enhancer.setCallback(methodInterceptor); return (T) enhancer.create(new Class[]{String.class},new Object[]{"Gavin"}); } public static void main(String[] args) { CglibProxy cglibProxy = new CglibProxy(new AnimalMethodInterceptor()); Person person = (Person) cglibProxy.getProxy(new Person("Gavin")); person.eat(); } }
输出:
Cglib proxy before method:eat Gavin Eating... Cglib proxy after method:eat
可以看到Cglib主要以继承的形式进行代理,那么Cglib就相应的无法对final类进行代理了,因为final类无法继承。
源码地址:https://github.com/gavincook/proxy
相关文章推荐
- java中的静态代理、动态代理以及Cglib代理
- java 笔记(3) —— 动态代理,静态代理,cglib代理
- Java静态代理以及动态代理使用详解
- java代理(静态代理和jdk动态代理以及cglib代理)
- Java中的动态代理以及Proxy类的偷瞄
- [Spring学习笔记 4 ] AOP 概念原理以及java动态代理
- Java动态代理与Cglib代理
- Java动态代理以及InvocationHandler中invoke()方法笔记
- 设计模式(3)-结构型-代理模式(proxy)以及java动态代理的两种方式
- JAVAWEB开发之Servlet3.0新特性的使用以及注解的详细使用和自定义注解的方法、动态代理的使用、利用动态代理实现细粒度的权限控制以及类加载和泛型反射
- (转)Java动态代理与CGLib代理
- java JDK 动态代理(如何使用,以及工作原理解析)
- 设计模式(3)-结构型-代理模式(proxy)以及java动态代理的两种方式
- 代理模式ProxyPattern以及java对此的支持——动态代理
- IT忍者神龟之Java动态代理与CGLib代理
- 从头认识java-12.5 代理以及动态代理
- IT忍者神龟之Java动态代理与CGLib代理
- Java动态代理模式jdk和cglib的2种实现以及二者的区别(AOP面向切面的前奏)
- JAVA JDK 动态代理以及Mybatis的理解
- 设计模式(3)-结构型-代理模式(proxy)以及java动态代理的两种方式