1. 程式人生 > >Spring AOP之代理設定模式

Spring AOP之代理設定模式

一.什麼是AOP

Spring的AOP:即面向切面程式設計,其程式碼實質,即代理模式的應用。

二.三種代理設定模式(目標物件不願意做的事,代理物件給我們實現)

代理模式程式碼的主要特點是:不改變原有類的前提下,在原有類某些方法執行前後,插入任意程式碼。所以代理模式需要寫新的類對原有的類進行包裝。代理模式目前實現的方式有三種: 這裡先定義一個介面

package com.offcn.test;

public interface Singer {
    public void singing();
    public void dancing();
}

在定義一個實現類

package com.
offcn.test; /** * 目標物件 */ public class WangBaoQiang implements Singer{ @Override public void singing() { System.out.println("正在唱歌"); } @Override public void dancing() { System.out.println("正在跳舞"); } }
  1. 靜態代理:需要增強原有類的哪個方法,就需要對在代理類中包裝哪個方法。個人理解,從功能上來說,原有類和代理類不一定要實現共同介面,但是為了賦予代理和和被代理類之間的邏輯關係,增加程式的可讀性,可理解性,邏輯性,增加代理物件和被代理物件之間的關係,以更加符合面向物件程式設計是思維,而應該實現共同介面。
    //首先例項化的物件是王寶強,就是目標物件
        Singer singer = new WangBaoQiang();

    //例項化代理物件來呼叫其方法(在呼叫目標物件的前後做一些相關的操作)
        ProxyWang proxyWang = new ProxyWang(singer);
        proxyWang.singing();
        //缺點:	擴充套件性差,每次只要有不同的目標物件,即使操作一樣,也要重新生成一個代理物件
		//優點:	好理解,程式碼看起來不復雜
  1. .動態代理(最常用):使用反射機制,方法和物件都是傳入的變數,就可以經過傳入的物件和方法而動態呼叫被代理物件的任何方法,jdk中提供了實現此動態代理的api(Proxy),被代理類必須實現介面
package com.offcn.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * 實現動態代理
 */
public class ProxyAi implements InvocationHandler {
    private Object object;
    public ProxyAi(Object object) {
        this.object = object;
    }
    //只要你的通過呼叫目標物件的方法都會走這個方法
    //第一個引數是代理物件,第二個引數是你呼叫目標物件的方法(通過反射來實現),第三個引數是你呼叫目標物件的方法裡的引數
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //通過反射來呼叫目標物件的方法,第一個引數你要呼叫目標物件方法的類,第二個引數是你要呼叫目標物件方法的引數
      Object o = null;
        if (method.getName().equals("singing")){
            System.out.println("試唱成功");
            o = method.invoke(object,args);
            System.out.println("唱歌結束");
        }else if (method.getName().equals("dancing")) {
            System.out.println("搭建舞臺成功");
            o = method.invoke(object, args);
            System.out.println("演出結束");
        }
        return o;
    }
}
  Singer singer = new WangBaoQiang();
            //jdk提供了一個代理類Proxy  第一個引數是類載入器,第二個引數是目標物件的class,第三個引數是代理物件
            //返回值型別是Object
        Singer singer1  = (Singer) Proxy.newProxyInstance(
                singer.getClass().getClassLoader(), new Class[]{Singer.class}, new ProxyAi(singer));
        singer1.singing();
  1. Cglib代理:返回物件是代理物件的子類,不需要代理物件實現介面。當呼叫原物件方法時,實際上呼叫的是代理子類的方法。

引入jar包 在這裡插入圖片描述

package com.offcn.test;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

//MethodInterceptor 方法攔截器
public class CglibProxy implements MethodInterceptor {

    //例項化物件
    private  Object object;
    //這個方法就是為了建立代理物件
     public  Object getCglibProxy(Object object){
        this.object=object;
        //得到建立代理物件的物件
         Enhancer enhancer = new Enhancer();

         //設定類載入器
         enhancer.setClassLoader(this.object.getClass().getClassLoader());

         //設定父類
         enhancer.setSuperclass(this.object.getClass());

         //設定回撥 ,只要走下面這個方法都要走回調
         enhancer.setCallback(this);

        // 建立代理物件
         return enhancer.create();
     }

     //這個方法就是在呼叫目標物件的方法都會執行這個方法
     //第一個引數是代理物件,第二個引數是目標物件的方法,第三個引數是目標物件的方法引數,第四個引數是代理物件攔截方法的物件
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("舞臺搭建成功");
        Object ob = method.invoke(object, objects);
        return ob;
    }
}

   //例項化一個cglibProxy代理物件類
        CglibProxy cglibProxy = new CglibProxy();
        Singer singer = new WangBaoQiang();
        Singer singer1 = (Singer) cglibProxy.getCglibProxy(singer);
        singer1.singing();