真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

什么是靜態(tài)代理與動(dòng)態(tài)代理

這篇文章主要介紹“什么是靜態(tài)代理與動(dòng)態(tài)代理”,在日常操作中,相信很多人在什么是靜態(tài)代理與動(dòng)態(tài)代理問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”什么是靜態(tài)代理與動(dòng)態(tài)代理”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

網(wǎng)站建設(shè)公司,為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁設(shè)計(jì)及定制網(wǎng)站建設(shè)服務(wù),專注于成都定制網(wǎng)頁設(shè)計(jì),高端網(wǎng)頁制作,對(duì)成都混凝土攪拌罐等多個(gè)行業(yè)擁有豐富的網(wǎng)站建設(shè)經(jīng)驗(yàn)的網(wǎng)站建設(shè)公司。專業(yè)網(wǎng)站設(shè)計(jì),網(wǎng)站優(yōu)化推廣哪家好,專業(yè)營(yíng)銷推廣優(yōu)化,H5建站,響應(yīng)式網(wǎng)站。

開場(chǎng)

一位穿著藍(lán)色襯衫,牛仔褲,拿著一個(gè)白色保溫杯的中年男子急匆匆地坐在你對(duì)面,看樣子是項(xiàng)目上的東西很急,估摸面試時(shí)間不會(huì)太長(zhǎng),這樣一想心情放松了許多......(后來我就被打臉了)

什么是靜態(tài)代理與動(dòng)態(tài)代理

面試開始

面試官:小伙子,我看你的簡(jiǎn)歷上說精通java基礎(chǔ)對(duì)吧,那我先簡(jiǎn)單來問幾個(gè)java基礎(chǔ)。

好的好的,面試官你問。(一聽到簡(jiǎn)單兩個(gè)字就內(nèi)心竊喜......)

面試官:你知道Java中有個(gè)東西叫代理嗎?

知道知道,代理就是通過代理對(duì)象去訪問實(shí)際的目標(biāo)對(duì)象,比如我們?cè)谏钪凶夥?,可以直接找房東,也可以通過某些租房平臺(tái)去租房,通過租房平臺(tái)的這種方式就是代理。在java中這種租房平臺(tái)就被叫做代理類,代理類不僅能實(shí)現(xiàn)目標(biāo)對(duì)象,還能增加一些額外的功能。據(jù)我所知java中的代理方式有靜態(tài)代理和動(dòng)態(tài)代理。(這個(gè)時(shí)候面試官很大概率會(huì)問你這兩種代理模式)。

面試官:沒想到你還能通過生活中的現(xiàn)象去理解代碼,不錯(cuò)不錯(cuò),我看你提到了靜態(tài)代理和動(dòng)態(tài)代理,那你給我說說什么是靜態(tài)代理吧

(果然問了,還好我做了準(zhǔn)備)靜態(tài)代理就是在代碼運(yùn)行之前,這個(gè)代理類就已經(jīng)存在了。還是以上面的租房為例,在代碼中會(huì)首先創(chuàng)建一個(gè)通用的租房接口:

public interface Room {
    void rent();
}

然后需要有一個(gè)被代理的類(或者稱為真實(shí)的類)和一個(gè)代理類:

public class RealRoom implements Room {
    private String roomname;
    public RealRoom(String roomname) {
        this.roomname = roomname;
    }
    public void rent() {
        System.out.println("租了"+roomname);
    }
}

代理類如下:

public class ProxyClass implements Room {
    RealRoom realRoom;
    public ProxyClass(RealRoom realRoom) {
        this.realRoom = realRoom;
    }
    public void rent() {
        System.out.println("租房前收取中介費(fèi)");
        realRoom.rent();
        System.out.println("租房后收取服務(wù)費(fèi)");
    }
}

代理類可以在不改變被代理對(duì)象的情況下增加功能,最后我們測(cè)試一下這個(gè)靜態(tài)代理:

public class Main {
    public static void main(String[] args) {
        RealRoom realRoom =new RealRoom("碧桂園");
        ProxyClass proxyClass=new ProxyClass(realRoom);
        proxyClass.rent();
    }
}

然后觀察結(jié)果:

租房前收取中介費(fèi)
租了碧桂園
租房后收取服務(wù)費(fèi)

面試官:既然靜態(tài)代理那么強(qiáng)大,那他有什么缺點(diǎn)嗎?

由于靜態(tài)代理在代碼運(yùn)行之前就已經(jīng)存在代理類,因此對(duì)于每一個(gè)代理對(duì)象都需要建一個(gè)代理類去代理,當(dāng)需要代理的對(duì)象很多時(shí)就需要?jiǎng)?chuàng)建很多的代理類,嚴(yán)重降低程序的可維護(hù)性。用動(dòng)態(tài)代理就可以解決這個(gè)問題。

面試官:那你給我講一講動(dòng)態(tài)代理吧

動(dòng)態(tài)代理是指代理類不是寫在代碼中,而是在運(yùn)行過程中產(chǎn)生的,java提供了兩種實(shí)現(xiàn)動(dòng)態(tài)代理的方式,分別是基于Jdk的動(dòng)態(tài)代理和基于Cglib的動(dòng)態(tài)代理。

面試官:基于JDK的動(dòng)態(tài)代理我忘了,你給我復(fù)習(xí)復(fù)習(xí)。

(我???算了算了) 實(shí)現(xiàn)Jdk的動(dòng)態(tài)代理需要實(shí)現(xiàn)InvocationHandler接口,然后實(shí)現(xiàn)其中的invoke方法。如果代理的方法被調(diào)用,那么代理便會(huì)通知和轉(zhuǎn)發(fā)給內(nèi)部的 InvocationHandler 實(shí)現(xiàn)類invoke,由它實(shí)現(xiàn)處理內(nèi)容。

public class ProxyHandler implements InvocationHandler {
    Object object;
    public ProxyHandler(Object object) {
        this.object = object;
    }
    //proxy 代理對(duì)象
    //method 要實(shí)現(xiàn)的方法
    //args 方法的參數(shù)    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理執(zhí)行之前:"+method.getName());
        Object invoke = method.invoke(object, args);
        System.out.println("代理執(zhí)行之后:"+method.getName());
        return invoke;
    }
}

接下來在main方法中執(zhí)行動(dòng)態(tài)代理

public static void main(String[] args) {
    Room room=new RealRoom("碧桂園");
    //obj.getClass().getClassLoader()類加載器
    //obj.getClass().getInterfaces() 目標(biāo)類實(shí)現(xiàn)的接口
    //InvocationHandler對(duì)象
    InvocationHandler invocationHandler=new ProxyHandler(room);
    Room proxyRoom = (Room) Proxy.newProxyInstance(room.getClass().getClassLoader(), room.getClass().getInterfaces(), invocationHandler);
    proxyRoom.rent();
}

這段代碼的核心是Proxy.newProxyInstance,目的是運(yùn)行期間生成代理類,最后通過代理類執(zhí)行被代理的方法。最后結(jié)果如下:

代理執(zhí)行之前:rent
租了碧桂園
代理執(zhí)行之后:rent

面試官:被你這么一說我想起來動(dòng)態(tài)代理了,那他的優(yōu)勢(shì)呢?

之前我講靜態(tài)代理的時(shí)候說靜態(tài)代理的缺點(diǎn)在于對(duì)于每一個(gè)被代理的對(duì)象,都需要建一個(gè)代理類。因?yàn)殪o態(tài)代理是在項(xiàng)目運(yùn)行前就寫好的。但是動(dòng)態(tài)代理就不是這樣,由于動(dòng)態(tài)代理在運(yùn)行時(shí)才創(chuàng)建代理類,因此只需要寫一個(gè)動(dòng)態(tài)代理類就好。比如我再創(chuàng)建一個(gè)被代理的對(duì)象賣房:

寫一個(gè)通用接口Sell

public interface Sell {
    void sellRoom();
}

接著還是寫一個(gè)被代理對(duì)象的類:

public class RealSell implements Sell {
    public void sellRoom() {
        System.out.println("賣房了");
    }
}

接下來在main方法中執(zhí)行動(dòng)態(tài)代理

    public static void main(String[] args) {
        Sell sell=new RealSell();
        InvocationHandler invocationHandler=new ProxyHandler(sell);
        Sell proxysell= (Sell) Proxy.newProxyInstance(sell.getClass().getClassLoader(),sell.getClass().getInterfaces(),invocationHandler);
        proxysell.sellRoom();
    }

最終實(shí)現(xiàn)結(jié)果如下:

代理執(zhí)行之前:sellRoom
賣房了
代理執(zhí)行之后:sellRoom

通過動(dòng)態(tài)代理,我可以通過一個(gè)動(dòng)態(tài)代理類,去代理多個(gè)對(duì)象。

面試官:如果我記的沒錯(cuò),通過這種方式只能代理接口吧,我看你上面的例子也都是代理接口,那我如果想代理類該怎么辦呢?

jdk動(dòng)態(tài)代理確實(shí)只能代理接口,JDK動(dòng)態(tài)代理是基于接口的方式,換句話來說就是代理類和目標(biāo)類都實(shí)現(xiàn)同一個(gè)接口。如果想要代理類的話可以使用CGLib,CGLib動(dòng)態(tài)代理是代理類去繼承目標(biāo)類,然后實(shí)現(xiàn)目標(biāo)類的方法。

創(chuàng)建一個(gè)目標(biāo)類CGRoom

public class CGRoom {
    public void rent(String roomName){
        System.out.println("租了"+roomName);
    }
}

創(chuàng)建cglib的動(dòng)態(tài)代理類,繼承MethodInterceptor ,實(shí)現(xiàn)其中的intercept方法

public class MyMethodInterceptor implements MethodInterceptor {

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理執(zhí)行之前:"+method.getName());
        Object object=methodProxy.invokeSuper(o,objects);
        System.out.println("代理執(zhí)行之后:"+method.getName());
        return object;
    }
}

最后通過enhance對(duì)象來創(chuàng)建代理類

public static void main(String[] args) {
    //創(chuàng)建Enhancer對(duì)象,類似于JDK動(dòng)態(tài)代理的Proxy類,下一步就是設(shè)置幾個(gè)參數(shù)
    Enhancer enhancer=new Enhancer();
    //設(shè)置目標(biāo)類的字節(jié)碼文件
    enhancer.setSuperclass(CGRoom.class);
    //設(shè)置回調(diào)函數(shù)
    enhancer.setCallback(new MyMethodInterceptor());
    //創(chuàng)建代理對(duì)象
    CGRoom proxy= (CGRoom) enhancer.create();
    proxy.rent("碧桂園");
}

最終實(shí)現(xiàn)以下結(jié)果:

代理執(zhí)行之前:rent
租了碧桂園
代理執(zhí)行之后:rent

面試官:既然動(dòng)態(tài)代理被你說的這么牛,那你平常工作中有使用到嗎?

平常我的業(yè)務(wù)代碼中雖然幾乎沒有使用過動(dòng)態(tài)代理,但是我工作中使用的Spring系列框架中的AOP,以及RPC框架中都用到了動(dòng)態(tài)代理,以AOP為例,AOP通過動(dòng)態(tài)代理對(duì)目標(biāo)對(duì)象進(jìn)行了增強(qiáng),比如我們最常用的前置通知、后置通知等。

面試官:不錯(cuò)!下面再考你幾個(gè)基礎(chǔ),說說你對(duì)注解的理解,注解又解決了哪些問題?

Java語言中的類、方法、變量、參數(shù)和包都可以用注解標(biāo)記,程序運(yùn)行過程中我們可以獲取到相應(yīng)的注解以及注解中定義的內(nèi)容,比如說 Spring 中如果檢測(cè)到說你的類被 @Component注解標(biāo)記的話,Spring 容器在啟動(dòng)的時(shí)候就會(huì)把這個(gè)類歸為自己管理,這樣你就可以通過 @Autowired注解注入這個(gè)對(duì)象了。

面試官:那你知道如何自己去定義注解嗎?

知道知道,自定義注解主要有以下四步:

第一步通過@interface聲明注解:

public @interface Myannotation {
    String key() default "";
}

第二步通過四種元注解修飾注解:(面試的時(shí)候說出這四種注解就可以了)

元注解的作用就是負(fù)責(zé)其他注解,java中一共有四個(gè)元注解,分別是@Target,@Retention,@Documented,@Inherited,下面先介紹以下四種注解的作用:

@Target:Target說明了注解所修飾的對(duì)象范圍,取值(ElementType)有:

  1. 用于描述構(gòu)造器

  1. 用于描述屬性

  2. 用于描述局部變量

  1. 用于描述方法

  2. 用于描述包

  3.  用于描述參數(shù)

  4.  用于描述類、接口(包括注解類型)或者enum聲明

@Retention:Retention定義了注解的保留范圍,取值(RetentionPoicy)有:

  1. 在源文件中有效(即源文件保留)

  1. 在class文件中有效(即class保留)

  2. 在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留)

@Documented:Documented用于描述其它類型的annotation應(yīng)該被作為被標(biāo)注的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化。Documented是一個(gè)標(biāo)記注解,沒有成員。

@Inherited:Inherited 元注解是一個(gè)標(biāo)記注解,@Inherited闡述了某個(gè)被標(biāo)注的類型是被繼承的。如果一個(gè)使用了@Inherited修飾的annotation類型被用于一個(gè)class,則這個(gè)annotation將被用于該class的子類。 

@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Myannotation {
    String key() default "";
}

第三步使用注解,因?yàn)槎xTarget時(shí)定義了MEHTOD和FIELD,因此可以在屬性和方法中使用這個(gè)注解:

public class MyannotationTest {
    @Myannotation(key = "javayz")
    private String username;
}

第四步利用反射解析注解

public static void main(String[] args) {
    Class myclass=MyannotationTest.class;
    Field[] fields = myclass.getDeclaredFields();
    for (Field field :fields){
        if (field.isAnnotationPresent(Myannotation.class)){
            System.out.println("配置了自定義注解");
            Myannotation annotation = field.getAnnotation(Myannotation.class);
            System.out.println("屬性:"+field.getName()+"上的注解key為"+annotation.key());
        }
    }
}

輸出結(jié)果:

配置了自定義注解
屬性:username上的注解key為javayz

面試官:我看你上面第四步提到了反射是吧?那你給我講講什么是反射,它有啥特點(diǎn):

(我暈,我就說了反射兩個(gè)字啊,還好有準(zhǔn)備)JAVA 反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為 java 語言的反射機(jī)制。

在上面第四步利用反射解析注解中,我通過MyannotationTest.class獲取到了MyannotationTest的類對(duì)象,又用myclass.getDeclaredFields();獲取到了所有的屬性。這就是反射。

到此,關(guān)于“什么是靜態(tài)代理與動(dòng)態(tài)代理”的學(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ī)砀鄬?shí)用的文章!


文章名稱:什么是靜態(tài)代理與動(dòng)態(tài)代理
鏈接地址:http://weahome.cn/article/poiooo.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部