什么是動(dòng)態(tài)代理?
創(chuàng)新互聯(lián)公司堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的德清網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
先說(shuō)下靜態(tài)代理:
也即是說(shuō),在程序運(yùn)行前,已經(jīng)有了編譯好的類,這個(gè)就是靜態(tài)代理,
動(dòng)態(tài)代理:
也即,在程序運(yùn)行前, 代理類并不存在,而是在程序運(yùn)行時(shí),動(dòng)態(tài)生成的類是動(dòng)態(tài)代理類。
可能會(huì)有如下思考
代理模式是怎樣的?用什么技術(shù)實(shí)現(xiàn)?
為什么要使用代理模式呢?有什么好處?
動(dòng)態(tài)代理的應(yīng)用場(chǎng)景有哪些?
先說(shuō)說(shuō)動(dòng)態(tài)代理的實(shí)現(xiàn)吧:
動(dòng)態(tài)代理主要使用的是Java 反射技術(shù):
JavaAPI 中關(guān)于InvocationHandler有大致這么一段描述,每個(gè)代理類都要實(shí)現(xiàn)InvocationHandler這個(gè)接口,每個(gè)代理類都會(huì)關(guān)聯(lián)到一個(gè)handle,
當(dāng)一個(gè)代理類調(diào)用方法時(shí),會(huì)轉(zhuǎn)到InvocationHandler的Invoke方法進(jìn)行調(diào)用。
以下代碼有引用以為牛人代碼
看下InvocationHandler源碼,我這就不再寫(xiě)一遍了。
public interface InvocationHandler
{
public abstract Object invoke(Object obj, Method method, Object aobj[])
throws Throwable;
}
這個(gè)invoke方法中有幾個(gè)參數(shù) :
obj:表示我們要調(diào)用的真實(shí)對(duì)象
method:表示我們要調(diào)用的真實(shí)對(duì)象的某個(gè)方法。
aobj[] :表示真實(shí)對(duì)象某個(gè)方法接受的參數(shù)。
怎么用這個(gè)InvocationHandler 這個(gè)接口,主要看proxy這個(gè)類:
Proxy是創(chuàng)建一個(gè)代理對(duì)象的類
Proxy這個(gè)類有這個(gè)一個(gè)方法:是用的最多的方法
public static Object newProxyInstance(ClassLoader classloader, Class aclass[], InvocationHandler invocationhandler)
throws IllegalArgumentException
參數(shù):
classloader: 定義了由那個(gè)ClassLoader對(duì)對(duì)象進(jìn)行加載
aclass[]: 是為代理對(duì)象提供了哪些接口,表示代理對(duì)象實(shí)現(xiàn)了這些接口,
invocationhandler: 表示代理對(duì)象調(diào)用方法時(shí)會(huì)關(guān)聯(lián)到那個(gè)invocationhandler
主要通過(guò)類Proxy與接口invocationhandler實(shí)現(xiàn)動(dòng)態(tài)代理:
看下具體動(dòng)態(tài)代理實(shí)現(xiàn)加深理解:
1.首先肯定是需要一個(gè)接口的:
public interface UserService {
public String getName(int id);
public Integer getAge(int id);
}
還需要這個(gè)接口的實(shí)現(xiàn),也就是代理對(duì)象:
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;
}
}
還需要自定義一個(gè)invocationhandler ,自己實(shí)現(xiàn)invoke方法:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
private Object target;
MyInvocationHandler() {
super();
}
MyInvocationHandler(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;
}
}
}
最后再看下proxy是怎樣的使用這個(gè)接口,還有invocationhandler的
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class TestProxy {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
InvocationHandler invocationHandler = new MyInvocationHandler(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));
}
}
以上可以看到可以清晰理解proxy的newproxyInstance是用來(lái)生成代理對(duì)象的, userService是指向具體 的實(shí)現(xiàn)
UserServiceImpl
給newproxyInstance方法傳入實(shí)際的classLoader,實(shí)際類對(duì)應(yīng)的接口,與調(diào)用類方法的invocationhandler即可實(shí)現(xiàn):
System.out.println("++++++before " + method.getName() + "++++++");
其實(shí)上面這個(gè)一行代碼就有***性質(zhì),aop時(shí)再詳細(xì)討論.
上面可以看到 使用這個(gè)反射技術(shù)實(shí)現(xiàn)動(dòng)態(tài)代理,需要定義一個(gè)接口,但是有時(shí)候其實(shí)不想定義接口,只希望定義好實(shí)現(xiàn)類,然后你再在方法運(yùn)行前,運(yùn)行后加些內(nèi)容即可。
這個(gè)就考慮了一個(gè)CGLIB這個(gè)可是不錯(cuò)的使用CGLIB實(shí)現(xiàn)動(dòng)態(tài)代理很方便。
Cglib 采用的是ASM字節(jié)碼技術(shù),利用字節(jié)碼生成代理類。效率比反射要高,但是不能代理final修身的類,clglib元素是集成被代理的類。final類不能被繼承。
下面看下cglib具體實(shí)現(xiàn):
下載 cglib包和asm包,你的工程需要依賴這兩個(gè)包:
首先需要一個(gè)非final類,不再和反射一樣需要一個(gè)接口了
public class StudentService {
public String getName(){
System.out.println("------getName------");
return "Tom";
}
public Integer getID(){
System.out.println("------getID------");
return 10;
}
}
接下來(lái)就看怎么代理上面的類了,需要定義一個(gè)攔截器:
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
System.out.println("++++++before " + methodProxy.getSuperName()
+ "++++++");
System.out.println(method.getName());
Object o1 = methodProxy.invokeSuper(o, args);
System.out.println("++++++before " + methodProxy.getSuperName()
+ "++++++");
return o1;
}
}
上面的interceptf方法和invocationhandler中的invoke方法類似,通過(guò)interceptf來(lái)真正調(diào)用方法invokeSuper:
最后看下Cglb具體怎么代理StudentService這個(gè)類吧:
import net.sf.cglib.proxy.Enhancer;
public class TestCglib {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(StudentService.class);
enhancer.setCallback(cglibProxy);
StudentService o = (StudentService)enhancer.create();
System.out.println(o.getName());
// System.out.println(o.getID());
}
}
上面的o即是 代理類,該類可以訪問(wèn)真實(shí)的Studentservice方法:
運(yùn)行結(jié)果:無(wú)錫婦科檢查多少錢 http://www.120csfkyy.com/
++++++before CGLIB$getName$1++++++
getName
------getName------
++++++before CGLIB$getName$1++++++
Tom
使用Cglib 有啥好處?
看下面代碼:
public class TestCglib {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(StudentService.class);
enhancer.setCallback(cglibProxy);
StudentService o = (StudentService)enhancer.create();
System.out.println(o.getName());
// System.out.println(o.getID());
Enhancer enhancer1 = new Enhancer();
enhancer1.setSuperclass(UserServiceImpl.class);
enhancer1.setCallback(cglibProxy);
UserServiceImpl obj = (UserServiceImpl)enhancer1.create();
System.out.println(obj.getName(1));
// System.out.println(o.getID());
}
}
只要寫(xiě)一個(gè)
cglibProxy
就可以是實(shí)現(xiàn)
對(duì)UserServiceImpl 與 StudentService進(jìn)行代理
減少了代碼的繁瑣,只有有這么一個(gè)代理就夠了,其次方便維護(hù),解耦合,要是有問(wèn)題,只要去找 原始類就可以了
新聞名稱:Java動(dòng)態(tài)代理的理解與Cglib動(dòng)態(tài)代理實(shí)現(xiàn)
本文URL:http://jinyejixie.com/article24/psihje.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號(hào)、App設(shè)計(jì)、域名注冊(cè)、網(wǎng)站維護(hù)、網(wǎng)站改版、虛擬主機(jī)
聲明:本網(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)