Skip to content

Latest commit

 

History

History
330 lines (283 loc) · 8.12 KB

動態代理.md

File metadata and controls

330 lines (283 loc) · 8.12 KB

動態代理

介紹

  • 方法的作用: 在運行時,動態創建一組指定的街口的實現類對象。(在運行時,創建實現了指定的一組接口的對象)
interface A {
}
interface B {
}

Object o = 方法(new Class[]{A.class, B.class})
//o 實現了A和B兩個接口
  • Object proxyObject = Proxy.newProxyInstance(ClassLoader classLoader, Class[] interfaces, InvocationHandler h);
    • 方法作用: 動態創建實現了 interfaces 數組中所有指定接口的實現類對象
    • ClassLoader: 類加載器
      • 他是用來加載器的,把 .class 文件加載到內存,形成 Class 對象
    • Class[] interfaces: 指定要實現的接口們
    • InvocationHandler: 代理對象的所有方法(個別不執行)都會調用 InvocationHandler 的 invoke() 方法

Example

package pers.demo1.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.junit.Test;

public class Demo1 {
	@Test
	public void fun1() {
		/*
		 * 三大參數
		 * 1. ClassLoader
		 * 方法需要動態生成一個類,這個類實現了 A, B 接口,然後創建了這個類的對象
		 * 需要生成一個類,這個類也需要加載到方法區中,ClassLoader 來加載
		 * 
		 * 2. Class[] interfaces
		 * 他是要實現的接口們
		 * 
		 * 3. InvocationHandler
		 * 他是調用處理器
		 * 
		 * 代理對象的實現的所有接口中的方法,內容都是調用 InvocationHandler 的 invoke() 對象
		 */
		ClassLoader loader = this.getClass().getClassLoader();
		InvocationHandler h = new InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				System.out.println("你好動態代理");
				return "xxx";	
			}
		};
		// 使用三大參數創建代理對象
		Object o = Proxy.newProxyInstance(loader, new Class[]{A.class, B.class}, h);
		
		//強轉成 A 和 B 類型成功
		A a = (A) o;
		B b = (B) o;
		
//		a.a();
//		a.aa();
//		b.b();
//		b.bb();
		
//		System.out.println(o.getClass().getName());
		
		Object result = a.aaa("hello", 100);
		System.out.println(o);
	}
}

interface A {
	public void a();
	public void aa();
	public Object aaa(String s1, int i);
}

interface B {
	public void b();
	public void bb();
}

動態代理作用

AOP(面向切面編程),他與裝飾者模式有點相似,他比裝飾者模式還要靈活

InvocationHandler

public Object invoke(Object proxy, Method method, Object[] args);

  • invoke() 方法在什麼時候被調用
    • 在代理對象創建時? 錯誤的
    • 在調用代理對象所實現接口中的方法時? 正確的
  • Object proxy: 當前對象,即代理對象,在調用誰的方法
  • Method method: 當前被調用的方法 (目標方法)
  • Object[] args: 實參
  • 目標對象: 被增強的對象
  • 代理對象: 需要目標對象,然後在目標對象上添加了增強後的對象
  • 目標方法: 增強的內容
  • 代理對象 = 目標對象 + 增強

Example

//Waiter.java
package pers.demo2.test;

//服務員
public interface Waiter {
	//服務
	public void serve();
}

//ManWaiter.java
package pers.demo2.test;

public class ManWaiter implements Waiter {
	@Override
	public void serve() {
		System.out.println("服務中...");
	}
}

//Demo2.java
package pers.demo2.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.junit.Test;

public class Demo2 {
	@Test
	public void fun1() {
		Waiter manWaiter = new ManWaiter(); //目標對象
		//給出三個參數來創建方法,得到代理對象
		ClassLoader loader = this.getClass().getClassLoader();
		Class[] interfaces = {Waiter.class};
		InvocationHandler h = new WaiterInvocationHandler(manWaiter); //參數 manWaiter 表示目標對象
		//得到代理對象,代理對象就是在目標對象的基礎上進行了增強對象
		Waiter waiterProxy = (Waiter) Proxy.newProxyInstance(loader, interfaces, h);
		
		waiterProxy.serve(); //前面添加"您好",後面添加"再見"
	}
}

class WaiterInvocationHandler implements InvocationHandler {
	private Waiter waiter; //目標對象
	public WaiterInvocationHandler(Waiter waiter) {
		this.waiter = waiter;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//		System.out.println("您好");
		this.waiter.serve(); //調用目標對象的目標方法
//		System.out.println("再見");
		return null;
	}
}

//Waiter.java
package pers.demo3.test;

//服務員
public interface Waiter {
	//服務
	public void serve();
}

//ManWaiter.java
package pers.demo3.test;

public class ManWaiter implements Waiter {
	@Override
	public void serve() {
		System.out.println("服務中...");
	}
}

//BeforeAdvice.java
package pers.demo3.test;

/**
 * 前置增強
 * @author jack870131
 *
 */
public interface BeforeAdvice {
	public void before();
}

//AfterAdvice.java
package pers.demo3.test;

public interface AfterAdvice {
	public void after();
}

//ProxyFactory.java
package pers.demo3.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 用來生成代理對象
 * 他需要所有的參數
 *  - 目標對象
 * @author jack870131
 *
 */
/**
 * 1. 創建代理工廠
 * 2. 給工廠設置三樣東西:
 *  - 目標對象: setTargetObject(xxx);
 *  - 前置增強: setBeforeAdvice(該接口的實現)
 *  - 後置增強: setAfterAdvice(該接口的實現)
 * 3. 調用 createProxy() 得到代理對象
 *  - 執行代理對象方法時
 *  - 執行 BeforeAdvice 的 before()
 *  - 目標對象的目標方法
 *  - 執行 AfterAdvice 的 after()
 * @author jack870131
 *
 */
public class ProxyFactory {
	private Object targetObject; //目標對象
	private BeforeAdvice beforeAdvice; //前置增強
	private AfterAdvice afterAdvice; //後置增強
	
	/**
	 * 用來生成代理對象
	 * @return
	 */
	public Object createProxy() {
		/*
		 * 1. 給出三大參數
		 */
		ClassLoader loader = this.getClass().getClassLoader();
		Class[] interfaces = targetObject.getClass().getInterfaces();
		InvocationHandler h = new InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				/*
				 * 在調用代理對象的方法時會執行這裡的內容
				 */
				//執行前置對象
				if(beforeAdvice != null) {
					beforeAdvice.before();
				}
				
				Object result = method.invoke(targetObject, args); //執行目標對象的目標方法
				//執行後置增強
				if(afterAdvice != null) {
					afterAdvice.after();
				}
				
				//返回目標對象的返回值
				return result;
			}
		};
		/*
		 * 2. 得到代理對象
		 */
		Object proxyObject = Proxy.newProxyInstance(loader, interfaces, h);
		return proxyObject;
	}
	
	public Object getTargetObject() {
		return targetObject;
	}
	public void setTargetObject(Object targetObject) {
		this.targetObject = targetObject;
	}
	public BeforeAdvice getBeforeAdvice() {
		return beforeAdvice;
	}
	public void setBeforeAdvice(BeforeAdvice beforeAdvice) {
		this.beforeAdvice = beforeAdvice;
	}
	public AfterAdvice getAfterAdvice() {
		return afterAdvice;
	}
	public void setAfterAdvice(AfterAdvice afterAdvice) {
		this.afterAdvice = afterAdvice;
	}
}

//Demo3.java
package pers.demo3.test;

import org.junit.Test;

/**
 * 目標是讓目標對象和增強都可以切換
 * @author jack870131
 *
 */
public class Demo3 {
	@Test
	public void fun1() {
		ProxyFactory factory = new ProxyFactory(); //創建工廠
		factory.setTargetObject(new ManWaiter()); //設置目標對象
		factory.setBeforeAdvice(new BeforeAdvice() { //設置前置增強
			public void before() {
				System.out.println("您好");
			}
		});
		
		factory.setAfterAdvice(new AfterAdvice() { //設置後置增強
			public void after() {
				System.out.println("再見");
			}
		});
		
		Waiter waiter = (Waiter) factory.createProxy();
		waiter.serve();
	}
}