SSM學習—Spring(第五天學習記錄)

AOP前景提要

提出問題

①代碼混亂:越來越多的非業務需求(日誌和驗證等)加入後,原有的業務方法急劇膨脹。每個方法在處理核心邏輯的同時還必須兼顧其他多個關注點。
②代碼分散: 以日誌需求爲例,只是爲了滿足這個單一需求,就不得不在多個模塊(方法)裏多次重複相同的日誌代碼。如果日誌需求發生變化,必須修改所有模塊。

動態代理

  • 代理設計模式的原理:使用一個代理將對象包裝起來,然後用該代理對象取代原始對象。任何對原始對象的調用都要通過代理。代理對象決定是否以及何時將方法調用轉到原始對象上。
    在這裏插入圖片描述
  • 代理的方式
 - 基於接口的動態代理:JDK動態代理

  		   Proxy:所有動態代理類的父類,專門用戶生成代理類或者代理對象
               public static Class<?> getProxyClass(ClassLoader loader,
                                               Class<?>... interfaces)
                                  用於生成代理類的Class對象.
               public static Object newProxyInstance(ClassLoader loader,
                                                Class<?>[] interfaces,
                                               InvocationHandler h)
                                  用於生成代理對象
          InvocationHandler :完成動態代理的整個過程.
       		public Object invoke(Object proxy, Method method, Object[] args)
              	throws Throwable;
 

在這裏插入圖片描述
附上代碼:

public interface ArithmeticCalculator {
    public  int   add(int i,int j);
    public  int sub(int i,int j);
    public  int mul(int i,int j);
    public int div(int i,int j);
}

public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

	@Override
	public int add(int i, int j) {
		int result = i + j ; 
		return result ; 
	}

	@Override
	public int sub(int i, int j) {
		int result = i - j ; 
		return result ; 
	}

	@Override
	public int mul(int i, int j) {
		int result = i * j ; 
		return result ; 
	}

	@Override
	public int div(int i, int j) {
		int result = i / j ; 
		return result ;
	}
	}


創建InvocationHandler類,實現InvocationHandler接口,這個類中持有一個被代理對象的實例target。InvocationHandler中有一個invoke方法,所有執行代理對象的方法都會被替換成執行invoke方法。再在invoke方法中執行被代理對象target的相應方法。當然,在代理過程中,我們在真正執行被代理對象的方法前加入自己其他處理。這也是Spring中的AOP實現的主要原理,這裏還涉及到很重要的關於java反射方面的基礎知識。

	public class ArithmeticCalculatorProxy {
	//目標對象
	private  ArithmeticCalculator  target ; 
	
	public ArithmeticCalculatorProxy(ArithmeticCalculator target) {
		this.target = target ; 
	}
	//獲取代理對象的方法
	public Object  getProxy() {
		//代理對象
		Object  proxy ; 
		/**
		 * loader:  ClassLoader對象。 類加載器對象.  幫我們加載動態生成的代理類。 
		 * 
		 * interfaces: 接口們.  提供目標對象的所有的接口.  目的是讓代理對象保證與目標對象都有接口中想同的方法. 
		 * 			
		 * h:  InvocationHandler類型的對象. 
		 */
		ClassLoader loader = target.getClass().getClassLoader();
		
		Class []  interfaces = target.getClass().getInterfaces();
		
		//執行newProxyInstance不會調用invoke
		proxy = Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {
			/**
			 * invoke:  代理對象調用代理方法, 會回來調用invoke方法。
			 * 
			 * proxy: 代理對象 , 在invoke方法中一般不會使用. 
			 * 
			 * method: 正在被調用的方法對象. 
			 * 
			 * args:   正在被調用的方法的參數. 
			 */
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				
				//將方法的調用轉回到目標對象上. 
				
				//獲取方法的名字
				String methodName = method.getName();
				//記錄日誌
				System.out.println("LoggingProxy==> The method " + methodName+" begin with "+ Arrays.asList(args));
				Object result = method.invoke(target, args);  // 目標對象執行目標方法. 相當於執行ArithmeticCalculatorImpl中的+ - * /
				
				//記錄日誌
				System.out.println("LoggingProxy==> The method " + methodName  +" ends with :" +result   );
				return result ;
			}
		});
		
		return proxy ;
	}
	
}

JDK動態代理的另外一種方式

public class ArithmeticCalculatorProxy2 {
	//動態代理:    目標對象     如何獲取代理對象      代理要做什麼 
	
	//目標對象
	private  ArithmeticCalculator  target ; 
	
	
	public ArithmeticCalculatorProxy2(ArithmeticCalculator target) {
		this.target = target ; 
	}
	
	
	//獲取代理對象的方法
	public Object  getProxy() throws Exception {
		
		//代理對象
		Object  proxy ; 
		
		ClassLoader loader = target.getClass().getClassLoader();
		Class [] interfaces = target.getClass().getInterfaces();
		
		Class proxyClass = Proxy.getProxyClass(loader, interfaces);
		
		//Class  創建對象?   newInstance()
		
		Constructor con = 
				proxyClass.getDeclaredConstructor(InvocationHandler.class);
		
		proxy = con.newInstance(new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				//將方法的調用轉回到目標對象上. 
				
				//獲取方法的名字
				String methodName = method.getName();
				//記錄日誌
				System.out.println("LoggingProxy2==> The method " + methodName+" begin with "+ Arrays.asList(args));
				Object result = method.invoke(target, args);  // 目標對象執行目標方法. 相當於執行ArithmeticCalculatorImpl中的+ - * /
				
				//記錄日誌
				System.out.println("LoggingProxy2==> The method " + methodName  +" ends with :" +result   );
				return result ;
			}
		});
		
		
		return proxy ;
	}
	
}

創建代理對象並進行測試

 public static void main(String[] args) {
           //將動態生成的proxy保存下來
        Properties properties = System.getProperties();
        properties.put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        //目標對象
        ArithmeticCalculator target =new ArithmeticCalculatorimpl();
        //獲取代理對象
        Object obj=new Proxy(target).getProxy();
        ArithmeticCalculator arithmeticCalculator=(ArithmeticCalculator)obj;
        System.out.println(arithmeticCalculator.getClass().getName());
        System.out.println(arithmeticCalculator.add(1,2));
    }

測試結果如下
在這裏插入圖片描述
生成的Proxy

package com.atguigu.spring.aop.proxy;

import com.atguigu.spring.aop.proxy.ArithmeticCalculator;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy00 extends Proxy implements ArithmeticCalculator {
	private static Method m1;
	private static Method m2;
	private static Method m4;
	private static Method m3;
	private static Method m6;
	private static Method m5;
	private static Method m0;

	public $Proxy00(InvocationHandler arg0) throws  {
      super(arg0);
   }

	public final boolean equals(Object arg0) throws  {
      try {
         return ((Boolean)super.h.invoke(this, m1, new Object[]{arg0})).booleanValue();
         //這裏又返回了InvocationHandler中的invoke方法
      } catch (RuntimeException | Error arg2) {
         throw arg2;
      } catch (Throwable arg3) {
         throw new UndeclaredThrowableException(arg3);
      }
   }

	public final String toString() throws  {
      try {
         return (String)super.h.invoke(this, m2, (Object[])null);
      } catch (RuntimeException | Error arg1) {
         throw arg1;
      } catch (Throwable arg2) {
         throw new UndeclaredThrowableException(arg2);
      }
   }

	public final int mul(int arg0, int arg1) throws  {
      try {
         return ((Integer)super.h.invoke(this, m4, new Object[]{Integer.valueOf(arg0), Integer.valueOf(arg1)})).intValue();
      } catch (RuntimeException | Error arg3) {
         throw arg3;
      } catch (Throwable arg4) {
         throw new UndeclaredThrowableException(arg4);
      }
   }

	public final int add(int arg0, int arg1) throws  {
      try {
         return ((Integer)super.h.invoke(this, m3, new Object[]{Integer.valueOf(arg0), Integer.valueOf(arg1)})).intValue();
      } catch (RuntimeException | Error arg3) {
         throw arg3;
      } catch (Throwable arg4) {
         throw new UndeclaredThrowableException(arg4);
      }
   }

	public final int sub(int arg0, int arg1) throws  {
      try {
         return ((Integer)super.h.invoke(this, m6, new Object[]{Integer.valueOf(arg0), Integer.valueOf(arg1)})).intValue();
      } catch (RuntimeException | Error arg3) {
         throw arg3;
      } catch (Throwable arg4) {
         throw new UndeclaredThrowableException(arg4);
      }
   }

	public final int div(int arg0, int arg1) throws  {
      try {
         return ((Integer)super.h.invoke(this, m5, new Object[]{Integer.valueOf(arg0), Integer.valueOf(arg1)})).intValue();
      } catch (RuntimeException | Error arg3) {
         throw arg3;
      } catch (Throwable arg4) {
         throw new UndeclaredThrowableException(arg4);
      }
   }

	public final int hashCode() throws  {
      try {
         return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
      } catch (RuntimeException | Error arg1) {
         throw arg1;
      } catch (Throwable arg2) {
         throw new UndeclaredThrowableException(arg2);
      }
   }

	static {
		try {
			m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
			m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
			m4 = Class.forName("com.atguigu.spring.aop.proxy.ArithmeticCalculator").getMethod("mul",
					new Class[]{Integer.TYPE, Integer.TYPE});
			m3 = Class.forName("com.atguigu.spring.aop.proxy.ArithmeticCalculator").getMethod("add",
					new Class[]{Integer.TYPE, Integer.TYPE});
			m6 = Class.forName("com.atguigu.spring.aop.proxy.ArithmeticCalculator").getMethod("sub",
					new Class[]{Integer.TYPE, Integer.TYPE});
			m5 = Class.forName("com.atguigu.spring.aop.proxy.ArithmeticCalculator").getMethod("div",
					new Class[]{Integer.TYPE, Integer.TYPE});
		    m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
		} catch (NoSuchMethodException arg1) {
			throw new NoSuchMethodError(arg1.getMessage());
		} catch (ClassNotFoundException arg2) {
			throw new NoClassDefFoundError(arg2.getMessage());
		}
	}
}

結束語

代理對象能否轉換成目標對象的類型?
代理對象調用代理方法,爲什麼會執行 InvocationHandler中的invoke 方法?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章