CGLIB實現動態代理
阿新 • • 發佈:2020-08-15
介紹
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));
}
}
執行時建立一個物件