java動態代理的兩種實現方式
阿新 • • 發佈:2019-02-02
一說到動態代理,我們第一個想到肯定是大名鼎鼎的Spring AOP了。在AOP的原始碼中用到了兩種動態代理來實現攔截切入功能:jdk動態代理和cglib動態代理。兩種方法同時存在,各有優劣。jdk動態代理是由java內部的反射機制來實現的,cglib動態代理是通過繼承來實現的,底層則是藉助asm(Java 位元組碼操控框架)來實現的(採用位元組碼的方式,給A類建立一個子類B,子類B使用方法攔截的技術攔截所以父類的方法呼叫)。總的來說,反射機制在生成類的過程中比較高效,而asm在生成類之後的相關執行過程中比較高效(可以通過將asm生成的類進行快取,這樣解決asm生成類過程低效問題)。還有一點必須注意:jdk動態代理的應用前提,必須是目標類基於統一的介面。如果沒有上述前提,jdk動態代理不能應用。由此可以看出,jdk動態代理有一定的侷限性,cglib這種第三方類庫實現的動態代理應用更加廣泛,且在效率上更有優勢。。
公用的介面和實現類
public interface UserService {
public String getName(int id);
public Integer getAge(int id);
}
public class UserServiceImpl implements UserService { @Override public String getName(int id) { System.out.println("------getName------"); return "Tom"; } @Override public Integer getAge(int id) { System.out.println("------getAge------"); return 10; } }
JDK的動態代理實現
jdk的動態代理,依賴的是反射包下的invocationHandler介面,我們的代理類實現invocationHandler,重寫invoke()方法,每當我們的代理類呼叫方法時,都會預設先經過invoke()方法。
public class UserInvocationHandler implements InvocationHandler { private Object target; UserInvocationHandler() { super(); } UserInvocationHandler(Object target) { super(); this.target = target; } @Override public Object invoke(Object o, Method method, Object[] args) throws Throwable { if("getName".equals(method.getName())){ System.out.println("++++++before " + method.getName() + "++++++"); Object result = method.invoke(target, args); System.out.println("++++++after " + method.getName() + "++++++"); return result; }else{ Object result = method.invoke(target, args); return result; } } }
測試類
public class M {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
InvocationHandler invocationHandler = new UserInvocationHandler(userService);
UserService userServiceProxy = (UserService) Proxy.newProxyInstance(
userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
invocationHandler);
System.out.println(userServiceProxy.getName(1));
System.out.println(userServiceProxy.getAge(1));
}
}
測試效果
CGLIB的動態代理實現
cglib依賴的是cglib包下的methodInterceptor介面,每呼叫代理類的方法,都會呼叫intercept方法public class CglibMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("------before " + methodProxy.getSuperName() + "------");
Object o1 = methodProxy.invokeSuper(o, args);
System.out.println("------after " + methodProxy.getSuperName() + "------");
return o1;
}
}
測試類
public class M {
public static void main(String[] args) {
CglibMethodInterceptor cglibProxy = new CglibMethodInterceptor();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class);
enhancer.setCallback(cglibProxy);
UserService o = (UserService) enhancer.create();
o.getName(1);
o.getAge(1);
}
}
測試結果