介绍
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没有这个限制,可以通过继承类的方式代理类。
方法拦截器的参数依次为:
- obj,表示创建的代理对象
- method,代理的方法,如sing
- objects,方法参数
- 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));
}
}
运行时创建一个对象