代理模式

思維導圖

代理模式導圖.png

前言

代理模式給某一個目標對象(target)提供代理對象(proxy),并由代理對象控制對target對象的引用夫否。

模式圖:

代理模式.png

代理模式中的角色有:

  • 抽象對象角色(AbstractObject):聲明了目標對象和代理對象的共同接口断序,這樣依賴在任何可以使用目標對象的地方都可以使用代理對象岖是。
  • 目標對象角色(RealObject):定義了代理對象所代表的目標對象棉圈。
  • 代理對象角色(ProxyObject):代理對象內(nèi)部含有目標對象的引用,從而可以在任何時候操作目標對象碰凶;代理對象提供一個與目標對象相同的接口,以便可以在任何時候替代目標對象鹿驼。代理對象通常在客戶端調(diào)用傳遞給目標對象之前或者之后欲低,執(zhí)行某個操作,而不是單純的將調(diào)用傳遞給目標對象畜晰。

按照代理類的創(chuàng)建時期砾莱,可分為靜態(tài)代理和動態(tài)代理:

  • 靜態(tài)代理:由程序員創(chuàng)建代理類或特定工具自動生成源代碼再對其編譯。在程序運行前代理類的.class文件就已經(jīng)存在了舷蟀。
  • 動態(tài)代理:在程序運行時運用反射機制動態(tài)創(chuàng)建而成恤磷。

靜態(tài)代理

實例:

1、抽象對象

public interface IDoctor {
    void display();
}

2野宜、目標對象

public class Doctor implements IDoctor {

    @Override
    public void display() {
        System.out.println("I am a doctor");
    }
}

3扫步、代理對象

public class DoctorProxy {

    private IDoctor iDoctor;

    public DoctorProxy() {
        this.iDoctor = new Doctor();
    }

    public void doProxy() {
        // 權限控制
        boolean isLogin = true;
        if (isLogin) {
            iDoctor.display();
        }
        // 記錄訪問日志
        System.out.println("記錄訪問日志");
    }
}

4、客戶端調(diào)用

public class StaticProxyTest {

    public static void main(String[] args) {
        DoctorProxy proxy = new DoctorProxy();
        proxy.doProxy();
    }
}

靜態(tài)代理在運行前就已經(jīng)確定了代理對象匈子,這種方式簡單河胎、效率高

但是靜態(tài)代理有以下缺點:

  1. 代理類和委托類實現(xiàn)了相同的接口,如果接口增加一個方法虎敦,除了所有實現(xiàn)類需要實現(xiàn)這個方法外游岳,所有代理類也需要實現(xiàn)此方法,因此增加了代碼維護的復雜度其徙。
  2. 代理對象只服務于一種類型的對象胚迫。如果還要為其他類提供代理的話,就需要我們再次添加代理類唾那。

動態(tài)代理

動態(tài)代理與靜態(tài)代理相比較访锻,最大的好處是接口中聲明的所有方法都被轉移到調(diào)用處理器一個集中的方法中處理。這樣闹获,在接口方法數(shù)量比較多的時候期犬,我們可以進行靈活處理,而不需要像靜態(tài)代理那樣每一個方法進行中轉避诽。而且動態(tài)代理的應用使我們的類職責更加單一龟虎,復用性更強。

JDK動態(tài)代理

利用攔截器(必須實現(xiàn)InvocationHandler)加上反射機制生成一個代理接口的匿名類沙庐,在調(diào)用具體方法前調(diào)用InvokeHandler來處理

實例:

1鲤妥、定義接口

public interface IStudent {
    void display();
}

2佳吞、目標對象

public class Student implements IStudent {
    @Override
    public void display() {
        System.out.println("I am a student");
    }
}

3、實現(xiàn)代理對象處理器接口

public class StudentHandler implements InvocationHandler {

    private IStudent student;

    public Object newProxyInstance(IStudent student) {
        this.student = student;
        return Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(proxy.getClass().getName());
        // 定義預處理的工作旭斥,當然你也可以根據(jù) method 的不同進行不同的預處理工作
        System.out.println("====before====");
        Object result = method.invoke(student, args);
        System.out.println("====after====");
        return result;
    }
}

4容达、測試

public class JdkProxyTest {

    public static void main(String[] args) {
        // 目標對象
        StudentHandler handler = new StudentHandler();

        // 動態(tài)生成代理對象
        IStudent proxy = (IStudent) handler.newProxyInstance(new Student());
        // 過代理對象調(diào)用方法
        proxy.display();
    }
}

CGLIB動態(tài)代理

上面的靜態(tài)代理和JDK動態(tài)代理需要目標對象是一個實現(xiàn)了接口的目標對象。但是有的時候垂券,目標對象可能只是一個單獨的對象花盐,并沒有實現(xiàn)任何的接口。這個時候菇爪,我們就可以使用Cglib代理方式算芯,它構建目標對象的子類對象,從而實現(xiàn)對目標對象的功能拓展凳宙。

利用ASM框架熙揍,對代理對象類生成的class文件加載進來,通過修改其字節(jié)碼生成子類來處理

實例:

1氏涩、引入POM:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

2届囚、目標類

public class Teacher {

    public void display() {
        System.out.println("I am a teacher");
    }
}

3、實現(xiàn)攔截器接口

public class CglibInterceptor implements MethodInterceptor {

    private Teacher teacher;

    // 獲取代理對象方法
    public Object getProxyInstance(Teacher teacher) {
        this.teacher = teacher;

        Enhancer enhancer = new Enhancer(); // 1 實例化工具類
        enhancer.setSuperclass(teacher.getClass()); // 設置父類對象
        enhancer.setCallback(this); // 設置回調(diào)函數(shù)
        return enhancer.create(); // 創(chuàng)建子類是尖,也就是代理對象
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before invoke");
        Object result = method.invoke(teacher, objects);
        System.out.println("after invoke");
        return result;
    }
}

4意系、測試

public class CglibProxyTest {

    public static void main(String[] args) {
        CglibInterceptor interceptor = new CglibInterceptor();
        Teacher proxy = (Teacher) interceptor.getProxyInstance(new Teacher());
        proxy.display();
    }
}

cglib和jdk動態(tài)代理區(qū)別

1、JDK動態(tài)代理只能對實現(xiàn)了接口的類生成代理饺汹,而不能針對類

2蛔添、Cglib是針對類實現(xiàn)代理,對指定的類生成一個子類兜辞,覆蓋其中的方法迎瞧,并對該方法實現(xiàn)增強。因為采用的是繼承逸吵,所以該類或方法不能是final的

框架應用

AOP

AOP(Aspect Oriented Programming凶硅,面向切面編程),像日志扫皱、安全咏尝、緩存、事務 等與業(yè)務邏輯分離的功能啸罢,可能會散布于各個業(yè)務bean,這樣的稱為 橫切關注點(cross-cutting concern)胎食。AOP有助于橫切關注點與它們所影響的對象之間解耦扰才。

AOP的實現(xiàn)主要是AspectJ(基于靜態(tài)代理)和Spring AOP(基于動態(tài)代理)

Spring AOP是目前市面上最為流行的AOP應用,下面只針對這個進行闡述

Spring AOP

AOP的實現(xiàn)原理是基于動態(tài)代理厕怜。在Spring AOP編程中:

  • 如果加入容器的目標對象有實現(xiàn)接口衩匣,就使用JDK代理
  • 如果目標對象沒有實現(xiàn)接口蕾总,就使用Cglib代理

除此之外,Spring AOP增加了AspectJ切點表達式語言的支持琅捏,并且可以無縫地集成AspectJ

實例:

1生百、引入POM

<!-- aop依賴 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2、service

@Service
public class BossService {

    public void display() {
        System.out.println("I am a boss");
    }
}

3柄延、controller

@RestController
@RequestMapping("/boss")
public class BossController {

    @Autowired
    private BossService bossService;

    @PostMapping("/display")
    public String display() {
        bossService.display();
        return "success";
    }
}

4蚀浆、切面

@Aspect
@Component
public class BossAspect {

    @Pointcut("execution(public * com.test.framework.springaop.BossService.*(..))")
    public void pointCut() {}

    @Before("pointCut()")
    public void before(JoinPoint point) throws Throwable {
        System.out.println("----- before ----");
    }

    @After("pointCut()")
    public void after(JoinPoint point) throws Throwable {
        System.out.println("----- after ----");
    }
}

5、測試

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

注意:

Spring AOP必須在Spring環(huán)境下使用

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搜吧,一起剝皮案震驚了整個濱河市市俊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滤奈,老刑警劉巖摆昧,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蜒程,居然都是意外死亡绅你,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門昭躺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忌锯,“玉大人,你說我怎么就攤上這事窍仰『汗妫” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵驹吮,是天一觀的道長针史。 經(jīng)常有香客問我,道長碟狞,這世上最難降的妖魔是什么啄枕? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮族沃,結果婚禮上频祝,老公的妹妹穿的比我還像新娘。我一直安慰自己脆淹,他們只是感情好常空,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著盖溺,像睡著了一般漓糙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烘嘱,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天昆禽,我揣著相機與錄音蝗蛙,去河邊找鬼。 笑死醉鳖,一個胖子當著我的面吹牛捡硅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播盗棵,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼壮韭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了漾根?” 一聲冷哼從身側響起泰涂,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辐怕,沒想到半個月后逼蒙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡寄疏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年是牢,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陕截。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡驳棱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出农曲,到底是詐尸還是另有隱情社搅,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布乳规,位于F島的核電站形葬,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏暮的。R本人自食惡果不足惜笙以,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望冻辩。 院中可真熱鬧猖腕,春花似錦、人聲如沸恨闪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咙咽。三九已至侠仇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背逻炊。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留犁享,地道東北人余素。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像炊昆,于是被迫代替她去往敵國和親桨吊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344