JDK动态代理

  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 
  按照代理的创建时期,代理类可以分为两种。 
  静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
  动态代理:在程序运行时,运用反射机制动态创建而成。

  为什么使用动态代理?因为动态代理可以对请求进行任何处理。
  哪些地方需要动态代理?不允许直接访问某些类;对访问要做特殊处理等。
  目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。 Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现。

  以下为模拟案例,通过动态代理实现在方法调用前后向控制台输出两句字符串。

  定义一个HelloWorld接口:

  1. package com.ljq.test;
  2. /**
  3. * 定义一个HelloWorld接口
  4. *
  5. * @author jiqinlin
  6. *
  7. */
  8. public interface HelloWorld {
  9. public void sayHelloWorld();
  10. }

  类HelloWorldImpl是HelloWorld接口的实现:

  1. package com.ljq.test;
  2. /**
  3. * 类HelloWorldImpl是HelloWorld接口的实现
  4. *
  5. * @author jiqinlin
  6. *
  7. */
  8. public class HelloWorldImpl implements HelloWorld{
  9. public void sayHelloWorld() {
  10. System.out.println("HelloWorld!");
  11. }
  12. }

  HelloWorldHandler是 InvocationHandler接口实现:

  1. package com.ljq.test;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. /**
  5. * 实现在方法调用前后向控制台输出两句字符串
  6. *
  7. * @author jiqinlin
  8. *
  9. */
  10. public class HelloWorldHandler implements InvocationHandler{
  11. //要代理的原始对象
  12. private Object obj;
  13. public HelloWorldHandler(Object obj) {
  14. super();
  15. this.obj = obj;
  16. }
  17. /**
  18. * 在代理实例上处理方法调用并返回结果
  19. *
  20. * @param proxy 代理类
  21. * @param method 被代理的方法
  22. * @param args 该方法的参数数组
  23. */
  24. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  25. Object result = null;
  26. //调用之前
  27. doBefore();
  28. //调用原始对象的方法
  29. result=method.invoke(obj, args);
  30. //调用之后
  31. doAfter();
  32. return result;
  33. }
  34. private void doBefore(){
  35. System.out.println("before method invoke");
  36. }
  37. private void doAfter(){
  38. System.out.println("after method invoke");
  39. }
  40. }

  测试类:

  1. package com.ljq.test;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Proxy;
  4. public class HelloWorldTest {
  5. public static void main(String[] args) {
  6. HelloWorld helloWorld=new HelloWorldImpl();
  7. InvocationHandler handler=new HelloWorldHandler(helloWorld);
  8. //创建动态代理对象
  9. HelloWorld proxy=(HelloWorld)Proxy.newProxyInstance(
  10. helloWorld.getClass().getClassLoader(),
  11. helloWorld.getClass().getInterfaces(),
  12. handler);
  13. proxy.sayHelloWorld();
  14. }
  15. }

  运行结果为:

  1. before method invoke
  2. HelloWorld!
  3. after method invoke

  基本流程:用Proxy类创建目标类的动态代理,创建时需要指定一个自己实现InvocationHandler接口的回调类的对象,这个回调类中有一个invoke()用于拦截对目标类各个方法的调用。创建好代理后就可以直接在代理上调用目标对象的各个方法。

  JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。比如上面的HelloWorldImpl类,实现了HelloWorld接口,所以可以用JDK的动态代理。如果想代理没有实现接口的继承的类,该怎么办? CGLIB就是最好的选择(https://github.com/cglib/cglib,使用apache license 2.0)。其他比较有名的还有从JBoss项目衍生出来的Javassist(https://github.com/jboss-javassist/javassist),这里介绍Cglib。

Cglib代码生成库

  CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。其底层是通过小而快的字节码处理框架ASM(http://forge.ow2.org/projects/asm,使用BSD License)来转换字节码并生成新的类。大部分功能实际上是asm所提供的,CGlib只是封装了asm,简化了asm的操作,实现了在运行期动态生成新的class。

  CGlib被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截);最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其他机制实现的);EasyMock和jMock是通过使用模仿(moke)对象来测试java代码的包,它们都通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。

  CGLIB包的基本代码很少,但学起来有一定的困难,主要是缺少文档,API描述过于简单,这也是开源软件的一个不足之处。目前CGLIB的版本是cglib-2.2.jar,主要由一下部分组成:
  (1)net.sf.cglib.core:底层字节码处理类,他们大部分与ASM有关系。
  (2)net.sf.cglib.transform:编译期或运行期类和类文件的转换。
  (3)net.sf.cglib.proxy :实现创建代理和方法拦截器的类。
  (4)net.sf.cglib.reflect :实现快速反射和C#风格代理的类。
  (5)net.sf.cglib.util:集合排序工具类。
  (6)net.sf.cglib.beans:JavaBean相关的工具类。

  CGLIB包是在ASM之上的一个高级别的层。对代理那些没有实现接口的类非常有用。本质上,它是通过动态的生成一个子类去覆盖所要代理类的不是final的方法,并设置好callback,则原有类的每个方法调用就会转变成调用用户定义的拦截方法(interceptors),这比JDK动态代理方法快多了。可见,Cglib的原理是对指定的目标类动态生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类和final方法进行代理。

用Cglib创建动态代理

  下图表示Cglib常用到的几类。

图1 Cglib主要的接口

  创建一个具体类的代理时,通常要用到的CGLIB包的APIs:

  net.sf.cglib.proxy.Callback接口:在CGLIB包中是一个很关键的接口,所有被net.sf.cglib.proxy.Enhancer类调用的回调(callback)接口都要继承这个接口。

  net.sf.cglib.proxy.MethodInterceptor接口:是最通用的回调(callback)类型,它经常被AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法。

  1. public Object intercept(Object object, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;

  当net.sf.cglib.proxy.MethodInterceptor做为所有代理方法的回调 (callback)时,当对基于代理的方法调用时,在调用原对象的方法的之前会调用这个方法,如图下图所示。第一个参数是代理对像,第二和第三个参数分别 是拦截的方法和方法的参数。原来的方法可能通过使用java.lang.reflect.Method对象的一般反射调用,或者使用 net.sf.cglib.proxy.MethodProxy对象调用。net.sf.cglib.proxy.MethodProxy通常被首选使用,因为它更快。在这个方法中,我们可以在调用原方法之前或之后注入自己的代码。

图1

  net.sf.cglib.proxy.MethodInterceptor能够满足任何的拦截(interception )需要,当对有些情况下可能过度。为了简化和提高性能,CGLIB包提供了一些专门的回调(callback)类型。例如:

  net.sf.cglib.proxy.FixedValue:为提高性能,FixedValue回调对强制某一特别方法返回固定值是有用的。

  net.sf.cglib.proxy.NoOp:NoOp回调把对方法调用直接委派到这个方法在父类中的实现。

  net.sf.cglib.proxy.LazyLoader:当实际的对象需要延迟装载时,可以使用LazyLoader回调。一旦实际对象被装载,它将被每一个调用代理对象的方法使用。

  net.sf.cglib.proxy.Dispatcher:Dispathcer回调和LazyLoader回调有相同的特点,不同的是,当代理方法被调用时,装载对象的方法也总要被调用。

   net.sf.cglib.proxy.ProxyRefDispatcher:ProxyRefDispatcher回调和Dispatcher一样,不同的是,它可以把代理对象作为装载对象方法的一个参数传递。

  代理类的所以方法经常会用到回调(callback),当然你也可以使用net.sf.cglib.proxy.CallbackFilter 有选择的对一些方法使用回调(callback),这种考虑周详的控制特性在JDK的动态代理中是没有的。在JDK代理中,对 java.lang.reflect.InvocationHandler方法的调用对代理类的所有方法都有效。

  CGLIB的代理包也对net.sf.cglib.proxy.Mixin提供支持。基本上,它允许多个对象被绑定到一个单一的大对象。在代理中对方法的调用委托到下面相应的对象中。

  接下来我们看看如何使 用CGLIB代理APIs创建代理。

  1、创建一个简单的代理

  CGLIB代理最核心类net.sf.cglib.proxy.Enhancer, 为了创建一个代理,最起码你要用到这个类。首先,让我们使用NoOp回调创建一个代理。

  1. /**
  2. * Create a proxy using NoOp callback. The target class
  3. * must have a default zero-argument constructor
  4. *
  5. * @param targetClass the super class of the proxy
  6. * @return a new proxy for a target class instance
  7. */
  8. public Object createProxy(Class targetClass) {
  9. Enhancer enhancer = new Enhancer();
  10. enhancer.setSuperclass(targetClass);
  11. enhancer.setCallback(NoOp.INSTANCE);
  12. return enhancer.create();
  13. }

  返回值是target类一个实例的代理。在这个例子中,我们为net.sf.cglib.proxy.Enhancer 配置了一个单一的回调(callback)。我们可以看到很少直接创建一个简单的代理,而是创建一个net.sf.cglib.proxy.Enhancer的实例,在net.sf.cglib.proxy.Enhancer类中你可使用静态帮助方法创建一个简单的代理。一般推荐使用上面例子的方法创建代理,因为它允许你通过配置net.sf.cglib.proxy.Enhancer实例很好的控制代理的创建。

  要注意的是,target类是作为产生的代理的父类传进来的。不同于JDK的动态代理,它不能在创建代理时传target对象,target对象必须被CGLIB包来创建。在这个例子中,默认的无参数构造器时用来创建target实例的。如果你想用CGLIB来创建有参数的实例,用net.sf.cglib.proxy.Enhancer.create(Class[], Object[])方法替代net.sf.cglib.proxy.Enhancer.create()就可以了。方法中第一个参数定义了参数的类型,第 二个是参数的值。在参数中,基本类型应被转化成类的类型。

  2、使用MethodInterceptor创建一个代理

  为了更好的使用代理,我们可以使用自己定义的MethodInterceptor类型回调(callback)来代替net.sf.cglib.proxy.NoOp回调。当对代理中所有方法的调用时,都会转向MethodInterceptor类型的拦截(intercept)方法,在拦截方法中再调用底层对象相应的方法。下面我们举个例子,假设你想对目标对象的所有方法调用进行权限的检查,如果没有经过授权,就抛出一个运行时的异常AuthorizationException。其中AuthorizationService.java接口的代码如下:

  1. package com.lizjason.cglibproxy;
  2. import java.lang.reflect.Method;
  3. /**
  4. * A simple authorization service for illustration purpose.
  5. * @author Jason Zhicheng Li (jason@lizjason.com)
  6. */
  7. public interface AuthorizationService {
  8. void authorize(Method method);
  9. }

  对net.sf.cglib.proxy.MethodInterceptor接口的实现的类AuthorizationInterceptor.java代码如下:

  1. package com.lizjason.cglibproxy.impl;
  2. import java.lang.reflect.Method;
  3. import net.sf.cglib.proxy.MethodInterceptor;
  4. import net.sf.cglib.proxy.MethodProxy;
  5. import com.lizjason.cglibproxy.AuthorizationService;
  6. /**
  7. * A simple MethodInterceptor implementation to
  8. * apply authorization checks for proxy method calls.
  9. */
  10. public class AuthorizationInterceptor implements MethodInterceptor {
  11. private AuthorizationService authorizationService;
  12. /**
  13. * Create a AuthorizationInterceptor with the given AuthorizationService
  14. */
  15. public AuthorizationInterceptor (AuthorizationService authorizationService) {
  16. this.authorizationService = authorizationService;
  17. }
  18. /**
  19. * Intercept the proxy method invocations to inject authorization check. * The original
  20. * method is invoked through MethodProxy.
  21. */
  22. public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
  23. if (authorizationService != null) {
  24. //may throw an AuthorizationException if authorization failed
  25. authorizationService.authorize(method);
  26. }
  27. return methodProxy.invokeSuper(object, args);
  28. }
  29. }

  我们可以看到在拦截方法中,首先进行权限的检查,如果通过权限的检查,拦截方法再调用目标对象的原始方法。由于性能的原因,对原始方法的调用我们使用CGLIB的net.sf.cglib.proxy.MethodProxy对象,而不是反射中一般使用java.lang.reflect.Method对象。

  下面是一个完整的使用MethodInterceptor的例子。

  1. package cglibexample;
  2. import java.lang.reflect.Method;
  3. import net.sf.cglib.proxy.Enhancer;
  4. import net.sf.cglib.proxy.MethodInterceptor;
  5. import net.sf.cglib.proxy.MethodProxy;
  6. /**
  7. * 定义一个HelloWorld类,没有实现接口
  8. *
  9. */
  10. class HelloWorld {
  11. public void sayHelloWorld() {
  12. System.out.println("HelloWorld!");
  13. }
  14. }
  15. /**
  16. * 通过Cglib实现在方法调用前后向控制台输出两句字符串
  17. *
  18. */
  19. class CglibProxy implements MethodInterceptor {
  20. //要代理的原始对象
  21. private Object obj;
  22. public Object createProxy(Object target) {
  23. this.obj = target;
  24. Enhancer enhancer = new Enhancer();
  25. // 设置要代理的目标类,以扩展它的功能
  26. enhancer.setSuperclass(this.obj.getClass());
  27. // 设置单一回调对象,在回调中拦截对目标方法的调用
  28. enhancer.setCallback(this);
  29. //设置类装载器
  30. enhancer.setClassLoader(target.getClass().getClassLoader());
  31. //创建代理对象
  32. return enhancer.create();
  33. }
  34. /**
  35. * 回调方法:在代理实例上拦截并处理目标方法的调用,返回结果
  36. *
  37. * @param proxy 代理类
  38. * @param method 被代理的方法
  39. * @param params 该方法的参数数组
  40. * @param methodProxy
  41. */
  42. @Override
  43. public Object intercept(Object proxy, Method method, Object[] params,
  44. MethodProxy methodProxy) throws Throwable {
  45. Object result = null;
  46. // 调用之前
  47. doBefore();
  48. // 调用目标方法,用methodProxy,
  49. // 而不是原始的method,以提高性能
  50. result = methodProxy.invokeSuper(proxy, params);
  51. // 调用之后
  52. doAfter();
  53. return result;
  54. }
  55. private void doBefore() {
  56. System.out.println("before method invoke");
  57. }
  58. private void doAfter() {
  59. System.out.println("after method invoke");
  60. }
  61. }
  62. public class TestCglib {
  63. public static void main(String[] args) {
  64. CglibProxy cglibProxy = new CglibProxy();
  65. HelloWorld hw = (HelloWorld) cglibProxy.createProxy(new HelloWorld());
  66. hw.sayHelloWorld();
  67. }
  68. }

  输出结果:

  1. before method invoke
  2. HelloWorld!
  3. after method invoke

  基本流程:需要自己写代理类,它实现MethodInterceptor接口,有一个intercept()回调方法用于拦截对目标方法的调用,里面使用methodProxy来调用目标方法。创建代理对象要用Enhance类,用它设置好代理的目标类、有intercept()回调的代理类实例、最后用create()创建并返回代理实例。

  3、使用CallbackFilter在方法层设置回调

  net.sf.cglib.proxy.CallbackFilter允许我们在方法层设置回调(callback)。假如你有一个PersistenceServiceImpl类,它有两个方法:save和load,其中方法save需要权限检查,而方法load不需要权限检查。

  1. import com.lizjason.cglibproxy.PersistenceService;
  2. import java.lang.reflect.Method;
  3. import net.sf.cglib.proxy.CallbackFilter;
  4. /**
  5. * A simple implementation of PersistenceService interface
  6. */
  7. class PersistenceServiceImpl implements PersistenceService {
  8. //需要权限检查
  9. public void save(long id, String data) {
  10. System.out.println(data + " has been saved successfully.");
  11. }
  12. //不需要权限检查
  13. public String load(long id) {
  14. return "Test CGLIB CallBackFilter";
  15. }
  16. }
  17. /**
  18. * An implementation of CallbackFilter for PersistenceServiceImpl
  19. */
  20. public class PersistenceServiceCallbackFilter implements CallbackFilter {
  21. //callback index for save method
  22. private static final int SAVE = 0;
  23. //callback index for load method
  24. private static final int LOAD = 1;
  25. /**
  26. * Specify which callback to use for the method being invoked.
  27. * @param method the method being invoked.
  28. * @return
  29. */
  30. @Override
  31. public int accept(Method method) {
  32. //指定各方法的代理回调索引
  33. String name = method.getName();
  34. if ("save".equals(name)) {
  35. return SAVE;
  36. }
  37. // for other methods, including the load method, use the
  38. // second callback
  39. return LOAD;
  40. }
  41. }

  accept方法中对代理方法和回调进行了匹配,返回的值是某方法在回调数组中的索引。下面是PersistenceServiceImpl类代理的实现。

  1. ...
  2. Enhancer enhancer = new Enhancer();
  3. enhancer.setSuperclass(PersistenceServiceImpl.class);
  4. //设置回调过滤器
  5. CallbackFilter callbackFilter = new PersistenceServiceCallbackFilter();
  6. enhancer.setCallbackFilter(callbackFilter);
  7. //创建各个目标方法的代理回调
  8. AuthorizationService authorizationService = ...
  9. Callback saveCallback = new AuthorizationInterceptor(authorizationService);
  10. Callback loadCallback = NoOp.INSTANCE;
  11. //顺序要与指定的回调索引一致
  12. Callback[] callbacks = new Callback[]{saveCallback, loadCallback };
  13. enhancer.setCallbacks(callbacks);  //设置回调
  14. ...
  15. return (PersistenceServiceImpl)enhancer.create();  //创建代理对象

  在这个例子中save方法使用了AuthorizationInterceptor实例,load方法使用了NoOp实例。此外,你也可以通过net.sf.cglib.proxy.Enhancer.setInterfaces(Class[])方法指定代理对象所实现的接口。

  除了为net.sf.cglib.proxy.Enhancer指定回调数组,你还可以通过net.sf.cglib.proxy.Enhancer.setCallbackTypes(Class[]) 方法指定回调类型数组。当创建代理时,如果你没有回调实例的数组,就可以使用回调类型。象使用回调一样,你必须使用net.sf.cglib.proxy.CallbackFilter为每一个方法指定一个回调类型索引。

  4、使用Mixin

  Mixin通过代理方式将多种类型的对象绑定到一个大对象上,这样对各个目标类型中的方法调用可以直接在这个大对象上进行。下面是一个例子。

  1. import net.sf.cglib.proxy.Mixin;
  2. interface MyInterfaceA {
  3. public void methodA();
  4. }
  5. interface MyInterfaceB {
  6. public void methodB();
  7. }
  8. class MyInterfaceAImpl implements MyInterfaceA {
  9. @Override
  10. public void methodA() {
  11. System.out.println("MyInterfaceAImpl.methodA()");
  12. }
  13. }
  14. class MyInterfaceBImpl implements MyInterfaceB {
  15. @Override
  16. public void methodB() {
  17. System.out.println("MyInterfaceBImpl.methodB()");
  18. }
  19. }
  20. public class Main {
  21. public static void main(String[] args) {
  22. //各个对象对应的类型
  23. Class[] interfaces = new Class[]{MyInterfaceA.class, MyInterfaceB.class};
  24. //各个对象
  25. Object[] delegates = new Object[]{new MyInterfaceAImpl(), new MyInterfaceBImpl()};
  26. //将多个对象绑定到一个大对象上
  27. Object obj = Mixin.create(interfaces, delegates);
  28. //直接在大对象上调用各个目标方法
  29. ((MyInterfaceA)obj).methodA();
  30. ((MyInterfaceB)obj).methodB();
  31. }
  32. }

动态生成Bean

  我们知道,Java Bean包含一组属性字段,用这些属性来存储和获取值。通过指定一组属性名和属性值的类型,我们可以使用Cglib的BeanGenerator和BeanMap来动态生成Bean。下面是一个例子。

  1. import java.lang.reflect.Method;
  2. import java.util.HashMap;
  3. import java.util.Iterator;
  4. import java.util.Map;
  5. import java.util.Set;
  6. import net.sf.cglib.beans.BeanGenerator;
  7. import net.sf.cglib.beans.BeanMap;
  8. /**
  9. * 动态实体bean
  10. *
  11. * @author cuiran
  12. * @version 1.0
  13. */
  14. class CglibBean {
  15. //Bean实体Object
  16. public Object object = null;
  17. //属性map
  18. public BeanMap beanMap = null;
  19. public CglibBean() {
  20. super();
  21. }
  22. @SuppressWarnings("unchecked")
  23. public CglibBean(Map<String, Class> propertyMap) {
  24. //用一组属性生成实体Bean
  25. this.object = generateBean(propertyMap);
  26. //用实体Bean创建BeanMap,以便可以设置和获取Bean属性的值
  27. this.beanMap = BeanMap.create(this.object);
  28. }
  29. /**
  30. * 给bean中的属性赋值
  31. *
  32. * @param property 属性名
  33. * @param value 值
  34. */
  35. public void setValue(String property, Object value) {
  36. beanMap.put(property, value);
  37. }
  38. /**
  39. * 获取bean中属性的值
  40. *
  41. * @param property 属性名
  42. * @return 值
  43. */
  44. public Object getValue(String property) {
  45. return beanMap.get(property);
  46. }
  47. /**
  48. * 得到该实体bean对象
  49. *
  50. * @return
  51. */
  52. public Object getObject() {
  53. return this.object;
  54. }
  55. @SuppressWarnings("unchecked")
  56. private Object generateBean(Map<String, Class> propertyMap) {
  57. //根据一组属性名和属性值的类型,动态创建Bean对象
  58. BeanGenerator generator = new BeanGenerator();
  59. Set keySet = propertyMap.keySet();
  60. for (Iterator i = keySet.iterator(); i.hasNext();) {
  61. String key = (String) i.next();
  62. generator.addProperty(key, (Class) propertyMap.get(key));
  63. }
  64. return generator.create();  //创建Bean
  65. }
  66. }
  67. /**
  68. * Cglib测试类
  69. *
  70. * @author cuiran
  71. * @version 1.0
  72. */
  73. public class CglibTest {
  74. @SuppressWarnings("unchecked")
  75. public static void main(String[] args) throws ClassNotFoundException { // 设置类成员属性
  76. HashMap<String, Class> propertyMap = new HashMap<>();
  77. propertyMap.put("id", Class.forName("java.lang.Integer"));
  78. propertyMap.put("name", Class.forName("java.lang.String"));
  79. propertyMap.put("address", Class.forName("java.lang.String")); // 生成动态Bean
  80. CglibBean bean = new CglibBean(propertyMap);
  81. // 给Bean设置值
  82. bean.setValue("id", 123);  //Auto-boxing
  83. bean.setValue("name", "454");
  84. bean.setValue("address", "789");
  85. // 从Bean中获取值,当然获得值的类型是Object
  86. System.out.println(" >> id = " + bean.getValue("id"));
  87. System.out.println(" >> name = " + bean.getValue("name"));
  88. System.out.println(" >> address = " + bean.getValue("address"));
  89. // 获得bean的实体
  90. Object object = bean.getObject();
  91. // 通过反射查看所有方法名
  92. Class clazz = object.getClass();
  93. Method[] methods = clazz.getDeclaredMethods();
  94. for (Method curMethod : methods) {
  95. System.out.println(curMethod.getName());
  96. }
  97. }
  98. }

  输出结果:

  1. >> id = 123
  2. >> name = 454
  3. >> address = 789
  4. getAddress
  5. getName
  6. getId
  7. setName
  8. setId
  9. setAddress

CGLIB轻松实现延迟加载

  通过使用LazyLoader,可以实现延迟加载,即在没有访问对象的字段或方法之前并不加载对象,只有当要访问对象的字段或方法时才进行加载。下面是一个例子。

  1. import net.sf.cglib.proxy.Enhancer;
  2. import net.sf.cglib.proxy.LazyLoader;
  3. class TestBean {
  4. private String userName;
  5. /**
  6. * @return the userName
  7. */
  8. public String getUserName() {
  9. return userName;
  10. }
  11. /**
  12. * @param userName the userName to set
  13. */
  14. public void setUserName(String userName) {
  15. this.userName = userName;
  16. }
  17. }
  18. //延迟加载代理类
  19. class LazyProxy implements LazyLoader {
  20. //拦截Bean的加载,本方法会延迟处理
  21. @Override
  22. public Object loadObject() throws Exception {
  23. System.out.println("开始延迟加载!");
  24. TestBean bean = new TestBean(); //创建实体Bean
  25. bean.setUserName("test");  //给一个属性赋值
  26. return bean;  //返回Bean
  27. }
  28. }
  29. public class BeanTest {
  30. public static void main(String[] args) {
  31. //创建Bean类型的延迟加载代理实例
  32. TestBean bean = (TestBean) Enhancer.create(TestBean.class, new LazyProxy());
  33. System.out.println("------");
  34. System.out.println(bean.getUserName());
  35. }
  36. }

  输出结果:

  1. ------
  2. 开始延迟加载!
  3. test

  我们创建TestBean类的延迟代理,通过LazyLoader中的loadObject()方法的拦截,实现对TestBean类的对象进行延迟加载。从输出可以看出,当创建延迟代理时,并没有立刻加载目标对象(因为还有输出“开始延迟加载!”),当通过代理访问目标对象的getUserName()方法时,就会加载目标对象。可见loadObject()是延迟执行的。

Java动态代理与Cglib库的更多相关文章

  1. java动态代理之CGLIB实现

    动态代理(CGlib 与连接池的案例) Cglib代理: 针对类来实现代理,对指定目标 产生一个子类 通过方法拦截技术拦截所有父类方法的调用. 我们要使用cglib代理必须引入 cglib的jar包 ...

  2. Java动态代理与CGLib

    Java帝国之动态代理 CGLib:从兄弟到父子-动态代理在民间是怎么玩的? 以上两篇文章引用自微信公众号: 码农翻身 Java动态代理 深度详解 以上文章引用博客园:陈树义

  3. JDK动态代理与Cglib库

    JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...

  4. (转)Java动态代理与CGLib代理

    <br>public class UserDAOImpl{ <br><br>    public void save() { <br>        / ...

  5. Java动态代理机制——Cglib

    上一篇说过JDK动态代理机制,只能代理实现了接口的类,这就造成了限制.对于没有实现接口的类,我们可以用Cglib动态代理机制来实现. Cglib是针对类生成代理,主要是对用户类生成一个子类.因为有继承 ...

  6. IT忍者神龟之Java动态代理与CGLib代理

    <br>public class UserDAOImpl{ <br><br>    public void save() { <br>        / ...

  7. java动态代理--proxy&cglib

    大纲 代理 proxy cglib 小结 一.代理 为什么要用代理?其实就是希望不修改对象的情况下,增强对象. 静态代理: 静态代理模式,需要代理类和目标类实现同一接口,代理类的方法调用目标类的方法, ...

  8. Proxy Pattern(Java动态代理和cglib的实现)

    代理模式:给某一个对象提供代理对象,由代理对象控制具体对象的引用. 代理,指的就是一个角色对表另一个角色采取行动,就生活中,一个红酒厂商,是不会直接把红酒零销给客户的,都是通过代理完成他的销售业务.而 ...

  9. 深入浅出Java动态代理

    文章首发于[博客园-陈树义],点击跳转到原文深入浅出Java动态代理 代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足轻重的地位.代理 ...

随机推荐

  1. Windows Phone 九、SQLite数据库

    使用SQLite数据库 安装 SQLite for Windows Phone 8.1 插件新建 Windows Phone 8.1 项目添加 SQLite for Windows Phone 8.1 ...

  2. rdesktop的使用方法

    工作时一般是开两台电脑 ,一台linux,一台windows,以前也用过虚拟机什么的,但是 有时候 跑起来拖泥带水的十分不爽,所以慢慢的就习惯了两台电脑的工作方式,一般我大部时间都在linux下面.用 ...

  3. win下命令行替代品Cmder

    Cmder简单使用小结 Cmder是一款Windows环境下非常简洁美观易用的cmd替代者,它支持了大部分的Linux命令. 从官网下载下来一个zip安装包,解压之后运行根目录的Cmder.exe即可 ...

  4. php读取excel内容

    使用php读取到excel文件中的内容 1.下载PHPExcel类 2.代码: header("Content-type:text/html;charset=utf-8");req ...

  5. c# 如何隐藏TabControl控件的标签

    http://www.cnblogs.com/chenleiustc/archive/2009/11/25/1527813.html 方法一:将标签缩小到机会看不到:设置页面的大小模式会自动适合(会尽 ...

  6. Configure Visual Studio 2013 for debugging .NET framework

    https://referencesource.microsoft.com/ In order to configure Visual Studio 2013 do the following in ...

  7. 从svn资源库目录checkout出maven项目方法

    从svn资源库目录checkout出maven项目方法,如下图所示:

  8. HashMap与ConcurrentHashMap的区别

    从JDK1.2起,就有了HashMap,正如前一篇文章所说,HashMap不是线程安全的,因此多线程操作时需要格外小心. 在JDK1.5中,伟大的Doug Lea给我们带来了concurrent包,从 ...

  9. 简单的HttpClient使用

    Httpclient用途很广泛,用来处理各种http请求,这里举个简单的例子 去查询QQ邮件登陆账号检测是的verifycode,一直想怎么能够代码登陆 QQ邮箱,但是QQ的登陆机制做的太TMD牛逼了 ...

  10. jQuery基本操作

    jQuery简介 jQuery是一个兼容多浏览器的javascript库,极大地简化了 JavaScript 编程,核心理念是write less,do more(写得更少,做得更多),对javasc ...