<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring AOP原理之動態(tài)代理

          共 6520字,需瀏覽 14分鐘

           ·

          2020-08-20 05:17



          什么是代理?


          指為一個目標(biāo)對象提供一個代理對象, 并由代理對象控制對目標(biāo)對象的引用. 使用代理對象, 是為了在不修改目標(biāo)對象的基礎(chǔ)上, 增強(qiáng)目標(biāo)對象的業(yè)務(wù)邏輯.



          靜態(tài)代理


          靜態(tài)代理的特點(diǎn)是, 為每一個業(yè)務(wù)增強(qiáng)都提供一個代理類, 由代理類來創(chuàng)建代理對象. 下面我們通過靜態(tài)代理來實(shí)現(xiàn)對轉(zhuǎn)賬業(yè)務(wù)進(jìn)行身份驗證.


          (1) 轉(zhuǎn)賬業(yè)務(wù)


          public?interface?IAccountService?{
          ????//主業(yè)務(wù)邏輯: 轉(zhuǎn)賬
          ????void?transfer();
          }
          public?class?AccountServiceImpl?implements?IAccountService?{
          ????@Override
          ????public?void?transfer()?{
          ????????System.out.println("調(diào)用dao層,完成轉(zhuǎn)賬主業(yè)務(wù).");
          ????}
          }


          (2) 代理類


          public?class?AccountProxy?implements?IAccountService?{
          ????//目標(biāo)對象
          ????private?IAccountService target;

          ????public?AccountProxy(IAccountService target) {
          ????????this.target = target;
          ????}

          ????/**
          ?????* 代理方法,實(shí)現(xiàn)對目標(biāo)方法的功能增強(qiáng)
          ?????*/

          ????@Override
          ????public?void?transfer()
          {
          ????????before();
          ????????target.transfer();
          ????}

          ????/**
          ?????* 前置增強(qiáng)
          ?????*/

          ????private?void?before() {
          ????????System.out.println("對轉(zhuǎn)賬人身份進(jìn)行驗證.");
          ????}
          }


          (3) 測試


          public?class?Client?{
          ????public?static?void?main(String[] args)?{
          ????????//創(chuàng)建目標(biāo)對象
          ????????IAccountService target = new?AccountServiceImpl();
          ????????//創(chuàng)建代理對象
          ????????AccountProxy proxy = new?AccountProxy(target);
          ????????proxy.transfer();
          ????}
          }

          結(jié)果:
          對轉(zhuǎn)賬人身份進(jìn)行驗證.
          調(diào)用dao層,完成轉(zhuǎn)賬主業(yè)務(wù).


          動態(tài)代理


          靜態(tài)代理會為每一個業(yè)務(wù)增強(qiáng)都提供一個代理類, 由代理類來創(chuàng)建代理對象, 而動態(tài)代理并不存在代理類, 代理對象直接由代理生成工具動態(tài)生成.


          JDK動態(tài)代理


          JDK動態(tài)代理是使用 java.lang.reflect 包下的代理類來實(shí)現(xiàn). JDK動態(tài)代理動態(tài)代理必須要有接口.


          (1) 轉(zhuǎn)賬業(yè)務(wù)


          public?interface?IAccountService?{
          ????//主業(yè)務(wù)邏輯: 轉(zhuǎn)賬
          ????void?transfer();
          }
          public?class?AccountServiceImpl?implements?IAccountService?{
          ????@Override
          ????public?void?transfer()?{
          ????????System.out.println("調(diào)用dao層,完成轉(zhuǎn)賬主業(yè)務(wù).");
          ????}
          }


          (2) 增強(qiáng)


          因為這里沒有配置切入點(diǎn), 稱為切面會有點(diǎn)奇怪, 所以稱為增強(qiáng).


          public?class?AccountAdvice?implements?InvocationHandler?{
          ????//目標(biāo)對象
          ????private?IAccountService target;

          ????public?AccountAdvice(IAccountService target)?{
          ????????this.target = target;
          ????}

          ????/**
          ?????* 代理方法, 每次調(diào)用目標(biāo)方法時都會進(jìn)到這里
          ?????*/

          ????@Override
          ????public?Object invoke(Object proxy, Method method, Object[] args)?throws?Throwable {
          ????????before();
          ????????return?method.invoke(target, args);
          ????}

          ????/**
          ?????* 前置增強(qiáng)
          ?????*/

          ????private?void?before()?{
          ????????System.out.println("對轉(zhuǎn)賬人身份進(jìn)行驗證.");
          ????}
          }


          (3) 測試


          public?class?Client?{
          ????public?static?void?main(String[] args)?{
          ????????//創(chuàng)建目標(biāo)對象
          ????????IAccountService target = new?AccountServiceImpl();
          ????????//創(chuàng)建代理對象
          ????????IAccountService proxy = (IAccountService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
          ????????????????target.getClass().getInterfaces(),
          ????????????????new?AccountAdvice(target)
          ????????);
          ????????proxy.transfer();
          ????}
          }
          結(jié)果:
          對轉(zhuǎn)賬人身份進(jìn)行驗證.
          調(diào)用dao層,完成轉(zhuǎn)賬主業(yè)務(wù).


          CGLIB動態(tài)代理


          JDK動態(tài)代理必須要有接口, 但如果要代理一個沒有接口的類該怎么辦呢? 這時我們可以使用CGLIB動態(tài)代理. CGLIB動態(tài)代理的原理是生成目標(biāo)類的子類, 這個子類對象就是代理對象, 代理對象是被增強(qiáng)過的.


          注意: 不管有沒有接口都可以使用CGLIB動態(tài)代理, 而不是只有在無接口的情況下才能使用.


          (1) 轉(zhuǎn)賬業(yè)務(wù)


          public?class?AccountService?{
          ????public?void?transfer() {
          ????????System.out.println("調(diào)用dao層,完成轉(zhuǎn)賬主業(yè)務(wù).");
          ????}
          }


          (2) 增強(qiáng)


          因為這里沒有配置切入點(diǎn), 稱為切面會有點(diǎn)奇怪, 所以稱為增強(qiáng).


          public?class?AccountAdvice implements?MethodInterceptor {
          ????/**
          ?????* 代理方法, 每次調(diào)用目標(biāo)方法時都會進(jìn)到這里
          ?????*/

          ????@Override
          ????public?Object?intercept(Object?obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
          ????????before();
          ????????return?methodProxy.invokeSuper(obj, args);
          ????????// return method.invoke(obj, args); 這種也行
          ????}

          ????/**
          ?????* 前置增強(qiáng)
          ?????*/

          ????private?void?before() {
          ????????System.out.println("對轉(zhuǎn)賬人身份進(jìn)行驗證.");
          ????}
          }


          (3) 測試


          public?class?Client?{
          ????public?static?void?main(String[] args)?{
          ????????//創(chuàng)建目標(biāo)對象
          ????????AccountService target = new?AccountService();
          ????????//
          ????????//創(chuàng)建代理對象
          ????????AccountService proxy = (AccountService) Enhancer.create(target.getClass(),
          ????????????????new?AccountAdvice());
          ????????proxy.transfer();
          ????}
          }
          結(jié)果:
          對轉(zhuǎn)賬人身份進(jìn)行驗證.
          調(diào)用dao層,完成轉(zhuǎn)賬主業(yè)務(wù).


          模擬Spring AOP場景


          了解了動態(tài)代理后, 我們就可以自己來實(shí)現(xiàn)Spring AOP功能了, 所以下面我們來模擬下Spring AOP場景.


          (1) 轉(zhuǎn)賬業(yè)務(wù)


          public?class?Client?{
          ????public?static?void?main(String[] args)?{
          ????????//創(chuàng)建目標(biāo)對象
          ????????AccountService target = new?AccountService();
          ????????//
          ????????//創(chuàng)建代理對象
          ????????AccountService proxy = (AccountService) Enhancer.create(target.getClass(),
          ????????????????new?AccountAdvice());
          ????????proxy.transfer();
          ????}
          }
          結(jié)果:
          對轉(zhuǎn)賬人身份進(jìn)行驗證.
          調(diào)用dao層,完成轉(zhuǎn)賬主業(yè)務(wù).


          (2) 切面抽象類


          定義一個切面抽象類, 該類使用了模板方法的設(shè)計模式, 為開始, 結(jié)束, 異常, 前置增強(qiáng), 后置增強(qiáng)提供了默認(rèn)實(shí)現(xiàn), 當(dāng)我們定義切面類時只需要按需重寫它們就行. isIntercept() 方法用來判斷切入點(diǎn)是否正確, 切面類需要重寫這個方法.



          public?abstract?class?BaseAspect?implements?MethodInterceptor?{
          ????private?static?final?Logger logger = LoggerFactory.getLogger(BaseAspect.class);

          ????@Override
          ????public?Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy)?throws?Throwable {
          ????????Object result = null;

          ????????begin();
          ????????try?{
          ????????????if?(isIntercept(method, args)) {
          ????????????????before();
          ????????????????result = methodProxy.invokeSuper(obj, args);
          ????????????????after();
          ????????????} else?{
          ????????????????result = methodProxy.invokeSuper(obj,args);
          ????????????}
          ????????} catch?(Exception e) {
          ????????????logger.error("proxy failure", e);
          ????????????error(e);
          ????????????throw?e;
          ????????} finally?{
          ????????????end();
          ????????}
          ????????return?result;
          ????}

          ????/**
          ?????* 開始增強(qiáng)
          ?????*/

          ????public?void?begin()?{
          ????}

          ????/**
          ?????* 切入點(diǎn)判斷
          ?????*/

          ????public?boolean?isIntercept(Method method, Object[] args)?throws?Throwable {
          ????????return?true;
          ????}

          ????/**
          ?????* 前置增強(qiáng)
          ?????*/

          ????public?void?before()?throws?Throwable {
          ????}

          ????/**
          ?????* 后置增強(qiáng)
          ?????*/

          ????public?void?after()?throws?Throwable {
          ????}

          ????/**
          ?????* 異常增強(qiáng)
          ?????*/

          ????public?void?error(Throwable e)?{
          ????}

          ????/**
          ?????* 最終增強(qiáng)
          ?????*/

          ????public?void?end()?{
          ????}
          }


          (3) 切面類


          創(chuàng)建一個切面類, 類中配置切入點(diǎn)和增強(qiáng).


          public?class?AccountAspect?extends?BaseAspect?{

          ????/**
          ?????* 切入點(diǎn)
          ?????*/

          ????public?boolean?isIntercept(Method method, Object[] args)?throws?Throwable {
          ????????return?method.getName().equals("transfer");
          ????}

          ????/**
          ?????* 前置增強(qiáng)
          ?????*/

          ????public?void?before()?throws?Throwable {
          ????????System.out.println("對轉(zhuǎn)賬人身份進(jìn)行驗證.");
          ????}
          }


          (4) 代理工廠類


          定義一個工廠類來創(chuàng)建代理, 其實(shí)不創(chuàng)建這個類也行, 但為了模仿Spring還是創(chuàng)建了. @SuppressWarnings是為了抑制警告, 就是編譯器上面的黃線.


          public?class?ProxyFactory?{

          ????@SuppressWarnings("unchecked")
          ????public?static? T createProxy(final?Class targetClass, final?MethodInterceptor methodInterceptor)?{
          ????????return?(T) Enhancer.create(targetClass,methodInterceptor);
          ????}
          }


          (5) 測試


          public?class?Client?{
          ????public?static?void?main(String[] args)?{
          ????????//創(chuàng)建目標(biāo)對象
          ????????IAccountService target = new?AccountServiceImpl();
          ????????//切面
          ????????BaseAspect accountAspect = new?AccountAspect();
          ????????//創(chuàng)建代理對象
          ????????IAccountService proxy = (IAccountService) ProxyFactory.createProxy(target.getClass(), accountAspect);
          ????????proxy.transfer();
          ????}
          }
          結(jié)果:
          對轉(zhuǎn)賬人身份進(jìn)行驗證.
          調(diào)用dao層,完成轉(zhuǎn)賬主業(yè)務(wù).


          原文鏈接:csdn.net/litianxiang_kaola/article/details/85335700



          瀏覽 63
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  午夜黄色大片 | 三级在线视频 | 免费成人艹逼无码视频 | 国内久久 | 综合电影Av |