這篇文章主要介紹“有哪些類代理的方式”,在日常操作中,相信很多人在有哪些類代理的方式問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”有哪些類代理的方式”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
創(chuàng)新互聯(lián)主營(yíng)大洼網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,成都app軟件開(kāi)發(fā),大洼h5成都微信小程序搭建,大洼網(wǎng)站營(yíng)銷推廣歡迎大洼等地區(qū)企業(yè)咨詢
不出意外
,你可能只知道兩種類代理的方式。一種是JDK自帶的,另外一種是CGLIB。
我們先定義出一個(gè)接口和相應(yīng)的實(shí)現(xiàn)類,方便后續(xù)使用代理類在方法中添加輸出信息。
「定義接口」
public interface IUserApi {
String queryUserInfo();
}
「實(shí)現(xiàn)接口」
public class UserApi implements IUserApi {
public String queryUserInfo() {
return "小傅哥,公眾號(hào):bugstack蟲(chóng)洞棧 | 沉淀、分享、成長(zhǎng),讓自己和他人都能有所收獲!";
}
}
好!接下來(lái)我們就給這個(gè)類方法使用代理加入一行額外輸出的信息。
@Test
public void test_reflect() throws Exception {
Class<UserApi> clazz = UserApi.class;
Method queryUserInfo = clazz.getMethod("queryUserInfo");
Object invoke = queryUserInfo.invoke(clazz.newInstance());
System.out.println(invoke);
}
public class JDKProxy {
public static <T> T getProxy(Class clazz) throws Exception {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return (T) Proxy.newProxyInstance(classLoader, new Class[]{clazz}, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + " 你被代理了,By JDKProxy!");
return "小傅哥,公眾號(hào):bugstack蟲(chóng)洞棧 | 沉淀、分享、成長(zhǎng),讓自己和他人都能有所收獲!";
}
});
}
}
@Test
public void test_JDKProxy() throws Exception {
IUserApi userApi = JDKProxy.getProxy(IUserApi.class);
String invoke = userApi.queryUserInfo();
logger.info("測(cè)試結(jié)果:{}", invoke);
}
/**
* 測(cè)試結(jié)果:
*
* queryUserInfo 你被代理了,By JDKProxy!
* 19:55:47.319 [main] INFO org.itstack.interview.test.ApiTest - 測(cè)試結(jié)果:小傅哥,公眾號(hào):bugstack蟲(chóng)洞棧 | 沉淀、分享、成長(zhǎng),讓自己和他人都能有所收獲!
*
* Process finished with exit code 0
*/
public class CglibProxy implements MethodInterceptor {
public Object newInstall(Object object) {
return Enhancer.create(object.getClass(), this);
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("我被CglibProxy代理了");
return methodProxy.invokeSuper(o, objects);
}
}
@Test
public void test_CglibProxy() throws Exception {
CglibProxy cglibProxy = new CglibProxy();
UserApi userApi = (UserApi) cglibProxy.newInstall(new UserApi());
String invoke = userApi.queryUserInfo();
logger.info("測(cè)試結(jié)果:{}", invoke);
}
/**
* 測(cè)試結(jié)果:
*
* queryUserInfo 你被代理了,By CglibProxy!
* 19:55:47.319 [main] INFO org.itstack.interview.test.ApiTest - 測(cè)試結(jié)果:小傅哥,公眾號(hào):bugstack蟲(chóng)洞棧 | 沉淀、分享、成長(zhǎng),讓自己和他人都能有所收獲!
*
* Process finished with exit code 0
*/
public class ASMProxy extends ClassLoader {
public static <T> T getProxy(Class clazz) throws Exception {
ClassReader classReader = new ClassReader(clazz.getName());
ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);
classReader.accept(new ClassVisitor(ASM5, classWriter) {
@Override
public MethodVisitor visitMethod(int access, final String name, String descriptor, String signature, String[] exceptions) {
// 方法過(guò)濾
if (!"queryUserInfo".equals(name))
return super.visitMethod(access, name, descriptor, signature, exceptions);
final MethodVisitor methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);
return new AdviceAdapter(ASM5, methodVisitor, access, name, descriptor) {
@Override
protected void onMethodEnter() {
// 執(zhí)行指令;獲取靜態(tài)屬性
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
// 加載常量 load constant
methodVisitor.visitLdcInsn(name + " 你被代理了,By ASM!");
// 調(diào)用方法
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
super.onMethodEnter();
}
};
}
}, ClassReader.EXPAND_FRAMES);
byte[] bytes = classWriter.toByteArray();
return (T) new ASMProxy().defineClass(clazz.getName(), bytes, 0, bytes.length).newInstance();
}
}
@Test
public void test_ASMProxy() throws Exception {
IUserApi userApi = ASMProxy.getProxy(UserApi.class);
String invoke = userApi.queryUserInfo();
logger.info("測(cè)試結(jié)果:{}", invoke);
}
/**
* 測(cè)試結(jié)果:
*
* queryUserInfo 你被代理了,By ASM!
* 20:12:26.791 [main] INFO org.itstack.interview.test.ApiTest - 測(cè)試結(jié)果:小傅哥,公眾號(hào):bugstack蟲(chóng)洞棧 | 沉淀、分享、成長(zhǎng),讓自己和他人都能有所收獲!
*
* Process finished with exit code 0
*/
Opcodes.GETSTATIC
、
Opcodes.INVOKEVIRTUAL
,除了這些還有小200個(gè)常用的指令。但這種最接近底層的方式,也是最快的方式。所以在一些使用字節(jié)碼插裝的全鏈路監(jiān)控中,會(huì)非常常見(jiàn)。public class ByteBuddyProxy {
public static <T> T getProxy(Class clazz) throws Exception {
DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
.subclass(clazz)
.method(ElementMatchers.<MethodDescription>named("queryUserInfo"))
.intercept(MethodDelegation.to(InvocationHandler.class))
.make();
return (T) dynamicType.load(Thread.currentThread().getContextClassLoader()).getLoaded().newInstance();
}
}
@RuntimeType
public static Object intercept(@Origin Method method, @AllArguments Object[] args, @SuperCall Callable<?> callable) throws Exception {
System.out.println(method.getName() + " 你被代理了,By Byte-Buddy!");
return callable.call();
}
@Test
public void test_ByteBuddyProxy() throws Exception {
IUserApi userApi = ByteBuddyProxy.getProxy(UserApi.class);
String invoke = userApi.queryUserInfo();
logger.info("測(cè)試結(jié)果:{}", invoke);
}
/**
* 測(cè)試結(jié)果:
*
* queryUserInfo 你被代理了,By Byte-Buddy!
* 20:19:44.498 [main] INFO org.itstack.interview.test.ApiTest - 測(cè)試結(jié)果:小傅哥,公眾號(hào):bugstack蟲(chóng)洞棧 | 沉淀、分享、成長(zhǎng),讓自己和他人都能有所收獲!
*
* Process finished with exit code 0
*/
Byte Buddy
也是一個(gè)字節(jié)碼操作的類庫(kù),但
Byte Buddy
的使用方式更加簡(jiǎn)單。無(wú)需理解字節(jié)碼指令,即可使用簡(jiǎn)單的 API 就能很容易操作字節(jié)碼,控制類和方法。比起JDK動(dòng)態(tài)代理、cglib,Byte Buddy在性能上具有一定的優(yōu)勢(shì)。
「另外」,2015年10月,Byte Buddy被 Oracle 授予了 Duke's Choice大獎(jiǎng)。該獎(jiǎng)項(xiàng)對(duì)Byte Buddy的“ Java技術(shù)方面的巨大創(chuàng)新 ”表示贊賞。public class JavassistProxy extends ClassLoader {
public static <T> T getProxy(Class clazz) throws Exception {
ClassPool pool = ClassPool.getDefault();
// 獲取類
CtClass ctClass = pool.get(clazz.getName());
// 獲取方法
CtMethod ctMethod = ctClass.getDeclaredMethod("queryUserInfo");
// 方法前加強(qiáng)
ctMethod.insertBefore("{System.out.println(\"" + ctMethod.getName() + " 你被代理了,By Javassist\");}");
byte[] bytes = ctClass.toBytecode();
return (T) new JavassistProxy().defineClass(clazz.getName(), bytes, 0, bytes.length).newInstance();
}
}
@Test
public void test_JavassistProxy() throws Exception {
IUserApi userApi = JavassistProxy.getProxy(UserApi.class)
String invoke = userApi.queryUserInfo();
logger.info("測(cè)試結(jié)果:{}", invoke);
}
/**
* 測(cè)試結(jié)果:
*
* queryUserInfo 你被代理了,By Javassist
* 20:23:39.139 [main] INFO org.itstack.interview.test.ApiTest - 測(cè)試結(jié)果:小傅哥,公眾號(hào):bugstack蟲(chóng)洞棧 | 沉淀、分享、成長(zhǎng),讓自己和他人都能有所收獲!
*
* Process finished with exit code 0
*/
Javassist
是一個(gè)使用非常廣的字節(jié)碼插裝框架,幾乎一大部分非入侵的全鏈路監(jiān)控都是會(huì)選擇使用這個(gè)框架。因?yàn)樗幌階SM那樣操作字節(jié)碼導(dǎo)致風(fēng)險(xiǎn),同時(shí)它的功能也非常齊全。另外,這個(gè)框架即可使用它所提供的方式直接編寫(xiě)插裝代碼,也可以使用字節(jié)碼指令進(jìn)行控制生成代碼,所以綜合來(lái)看也是一個(gè)非常不錯(cuò)的字節(jié)碼框架。到此,關(guān)于“有哪些類代理的方式”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
網(wǎng)站題目:有哪些類代理的方式
URL網(wǎng)址:http://m.rwnh.cn/article38/jcgjpp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開(kāi)發(fā)、電子商務(wù)、定制開(kāi)發(fā)、微信小程序、域名注冊(cè)、ChatGPT
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)