JDK动态代理与Cglib库

JDK动态代理

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

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

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

  定义一个HelloWorld接口:

[java] view plaincopy

  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接口的实现:

[java] view plaincopy

  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接口实现:

[java] view plaincopy

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

  测试类:

[java] view plaincopy

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

  运行结果为:

[plain] view plaincopy

  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)方法的调用。这个接口只定义了一个方法。

[java] view plaincopy

  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回调创建一个代理。

[java] view plaincopy

  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接口的代码如下:

[java] view plaincopy

  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 ([email protected])
  6. */
  7. public interface AuthorizationService {
  8. void authorize(Method method);
  9. }

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

[java] view plaincopy

  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的例子。

[java] view plaincopy

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

  输出结果:

[plain] view plaincopy

  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不需要权限检查。

[java] view plaincopy

  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类代理的实现。

[java] view plaincopy

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

[java] view plaincopy

  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。下面是一个例子。

[java] view plaincopy

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

  输出结果:

[java] view plaincopy

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

CGLIB轻松实现延迟加载

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

[java] view plaincopy

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

  输出结果:

[java] view plaincopy

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

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

时间: 2024-07-29 10:46:31

JDK动态代理与Cglib库的相关文章

Java进阶之 JDK动态代理与Cglib动态代理

一.动态代理概述: 与静态代理对照(关于静态代理的介绍 可以阅读上一篇:JAVA设计模式之 代理模式[Proxy Pattern]), 动态代理类的字节码是在程序运行时由Java反射机制动态生成. 注意: 1.AspectJ是采用编译时生成AOP代理类,具有更好的性能,但是需要使用特定的编译器进行处理 2.Spring AOP采用运行时生成AOP代理类,无需使用特定编译器进行处理,但是性能相对于AspectJ较差 二.JDK动态代理 [对有实现接口的对象做代理] 1.JDK动态代理中 需要了解的

Java学习之:JDK动态代理与CGLIB动态代理

代理的概念:简单的理解就是通过为某一个对象创建一个代理对象,我们不直接引用原本的对象,而是由创建的代理对象来控制对原对象的引用. 动态代理:是指在程序运行时由Java反射机制动态生成,无需手动编写代码.动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java反射机制可以生成任意类型的动态代理类. 代理原理:代理对象内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象.同时,代理对象可以在执行真实对象操作时,附加其他的操作

Spring AOP详解 、 JDK动态代理、CGLib动态代理

AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码通过横向切割的方式抽取到一个独立的模块中. 一.AOP术语 1.连接点(Joinpoint) 程序执行的某个特定位置:如类开始初始化之前.类初始化之后.类某个方法调用前.调用后等:一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就成为“连接点”,Spring仅支持方法的连接点,即

AOP学习心得&amp;jdk动态代理与cglib比较

什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合.当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力.也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系.例如日志功能.日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无

JDK动态代理与Cglib动态代理(转载)

spring容器通过动态代理再结合java反射思想可以使得方法调用更加简洁 一.动态代理概述: 与静态代理对照(关于静态代理的介绍 可以阅读上一篇:JAVA设计模式之 代理模式[Proxy Pattern](博主), 动态代理类的字节码是在程序运行时由Java反射机制动态生成. 注意:       1.AspectJ是采用编译时生成AOP代理类,具有更好的性能,但是需要使用特定的编译器进行处理 2.Spring AOP采用运行时生成AOP代理类,无需使用特定编译器进行处理,但是性能相对于Aspe

【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理

原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码通过横向切割的方式抽取到一个独立的模块中. 一.AOP术语 1.连接点(Joinpoint) 程序执行的某个特定位置:如类开始初始化之前.类初始化之后.类某个方法调用前.调用后等:一个类

Java动态代理与Cglib库

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

jdk动态代理与cglib代理、spring aop代理实现原理解析

原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 动态代理实现主要有2种形式,主要分为: 1.jdk动态代理: 1)原理:是根据类加载器和接口创建代理类(此代理类是接口的实现类,所以必须使用接口 面向接口生成代理,位于java.lang.reflect包下) 2)实现方式: 1. 通过实现Invocati

AOP、静态代理、JDK动态代理、CGLIB动态代理、Spring实现AOP、IOC+AOP

一.为什么需要代理模式 假设需实现一个计算的类Math.完成加.减.乘.除功能,如下所示: 1 package com.zhangguo.Spring041.aop01; 2 3 public class Math { 4 //加 5 public int add(int n1,int n2){ 6 int result=n1+n2; 7 System.out.println(n1+"+"+n2+"="+result); 8 return result; 9 } 1