CGLIB实现动态代理

介绍

cglib是一个强大的,受欢迎的,高性能的代码生成类库,它的底层就是asm(字节码框架),可以用来动态修改class和创建class,Spring AOP实现动态代理的一种方式就是cglib,hibernate使用cglib对持久化对象创建代理。

实现动态代理

引入maven依赖

<dependency>
   <groupId>cglib</groupId>
   <artifactId>cglib</artifactId>
   <version>3.3.0</version>
</dependency>

实现

public class Client {
  public static void main(String[] args) {
//设置cglib生成的源码目录
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\");
    Enhancer enhancer = new Enhancer();
//设置父类
    enhancer.setSuperclass(Singer.class);
//设置方法拦截处理器
    enhancer.setCallback(new SingerMethodInterceptor());
//创建代理对象
    Singable singable = (Singable) enhancer.create();
    singable.sing();
  }

  public static class SingerMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
      System.out.println("cglib before");
      Object result = methodProxy.invokeSuper(obj, objects);
      System.out.println("cglib after");
      return result;
    }
  }
}

输出结果为

cglib before
I am singing...
cglib after

可以看到确实实现了动态代理的功能,JDK动态代理创建的类默认继承Proxy类,所以不能继承其他类,cglib没有这个限制,可以通过继承类的方式代理类。
方法拦截器的参数依次为:

  1. obj,表示创建的代理对象
  2. method,代理的方法,如sing
  3. objects,方法参数
  4. methodProxy,封装了代理方法,代理对象和原对象

创建不可变对象

public class Client {
  public static void main(String[] args) {
    User user = new User("lisi");
//根据user对象创建一个不可变对象
    User immutableUser = (User) ImmutableBean.create(user);
    System.out.println(immutableUser);
//当我们修改了原对象,不可变对象也被修改了
    user.setName("lisi3");
    System.out.println(immutableUser);
    immutableUser.setName("lisi2");
    System.out.println(immutableUser);
  }

  @Getter
  @Setter
  @AllArgsConstructor
  @NoArgsConstructor
  @ToString
  public static class User {

    private String name;
  }
}

当我们修改不可变对象时,会抛出异常

Exception in thread "main" java.lang.IllegalStateException: Bean is immutable
	at com.imooc.sourcecode.java.dynamicproxy.cglib.test2.Client$User$$ImmutableBeanByCGLIB$$98871c2c.setName(<generated>)
	at com.imooc.sourcecode.java.dynamicproxy.cglib.test2.Client.main(Client.java:17)

但是如果我们修改原对象,那么不可变对象也会相应的被修改。这是因为不可变对象是通过继承原类,然后重写Getter,setter方法实现的,Getter直接调用原对象的Getter,setter直接抛出异常。

对象生成器

public class Client {
  public static void main(String[] args) throws Exception {
    BeanGenerator beanGenerator = new BeanGenerator();
    beanGenerator.addProperty("name", String.class);
    Object bean = beanGenerator.create();
    Method setNameMethod = bean.getClass().getMethod("setName", String.class);
    setNameMethod.invoke(bean,"lisi");
    Method getNameMethod = bean.getClass().getMethod("getName");
    System.out.println(getNameMethod.invoke(bean));
  }
}

运行时创建一个对象

posted @ 2020-08-15 21:50  strongmore  阅读(2882)  评论(0编辑  收藏  举报