概念及特點
- 使用CGLib實現動態代理,依賴cglib-x.x.x.jar
- 原理是對指定的業務類動態生成一個子類,並覆蓋其中業務方法實現代理
- 針對類來實現代理的,完全不受代理類必須實現接口的限制
- CGLib底層採用ASM字節碼生成框架,使用字節碼技術生成代理類
- 因爲採用的是繼承,所以不能對final修飾的類進行代理,不能對聲明爲final的方法進行代理
組成
- 業務實現類 負責實現主要的業務方法(不需要實現接口)
- 實現攔截接口MethodInterceptor,創建動態代理類
案例演示
-
引入cglib
<dependencies> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency> </dependencies>
-
業務實現類
public class AccountServiceImpl { public void queryAccount() { System.out.println("查看賬戶..."); } public void updateAccount() { System.out.println("修改賬戶..."); } }
-
方法攔截器
public class CglibProxy implements MethodInterceptor { private Object target;//業務類對象,供代理方法中進行真正的業務方法調用 //相當於JDK動態代理中的綁定 public Object getInstance(Object target) { this.target = target; //給業務對象賦值 Enhancer enhancer = new Enhancer(); //創建加強器,用來創建動態代理類 enhancer.setSuperclass(this.target.getClass()); //爲加強器指定要代理的業務類(即:爲下面生成的代理類指定父類) //設置回調:對於代理類上所有方法的調用,都會調用CallBack,而Callback則需要實現intercept()方法進行攔截 enhancer.setCallback(this); // 創建動態代理類對象並返回 return enhancer.create(); } // 實現回調方法 @Override public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("預處理——————"); proxy.invokeSuper(target, args); //調用業務類(父類中)的方法 System.out.println("調用後操作——————"); return null; } }
- 業務調用
public class CglibProxyApplication { public static void main(String[] args) { AccountServiceImpl accountServiceImpl=new AccountServiceImpl(); CglibProxy cglib=new CglibProxy(); AccountServiceImpl accountServiceProxy=(AccountServiceImpl)cglib.getInstance(accountServiceImpl); accountServiceProxy.queryAccount(); accountServiceProxy.updateAccount(); } }
兩種動態代理對比
- 機制區別
- jdk動態代理是通過接口中的方法名,在動態生成的代理類中調用業務實現類的同名方法;利用攔截器(攔截器必須實現InvocationHanlder)加上反射機制生成一個實現代理接口的匿名類;
- cglib動態代理是通過繼承業務類,生成的動態代理類是業務類的子類,通過重寫業務方法進行代理;cglib底層採用ASM字節碼生成框架,使用字節碼技術生成代理類;
- 效率對比
- jdk6之前,cglib效率過於jdk反射
- 調用次數較少時,jdk6、jdk7優於cglib
- 調用次數較多時,jdk6、jdk7反射效率低於cglib
- jdk8 動態代理優於cglib效率