天天看點

黑馬程式員-代理

---------------------- <a href="http://www.itheima.com" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="blank">ASP.Net+Unity開發</a>、<a href="http://www.itheima.com" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="blank">.Net教育訓練</a>、期待與您交流! ---------------------

代理:

黑馬程式員-代理

動态代理類:

JVM可以在運作期動态生成出類的位元組碼,這種動态生成的類往往被用作代理類,即動态代理。

JVM生成的動态類必須實作一個或多個接口,是以,JVM生成的動态類隻能用作具有相同接口的目标類的代理。

CGLIB庫可以動态生成一個類的子類,一個類的子類也可以用作該類的代理,是以,如果要為一個沒有實作接口的類生成動态代理類,那麼可以使用CGLIB庫。

黑馬程式員-代理

Proxy 提供用于建立動态代理類和執行個體的靜态方法,它還是由這些方法建立的所有動态代理類的超類。

現在想要建立一個Proxy,根據API提供的方法,

Class clazz=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);

首先需要明确一個接口,就是要代理的接口,然後第一個參數是一個類加載器,這個類加載器一般跟這個接口的類加載器相同。

現在我想列印出這個代理類的構造函數,以及這些構造函數的參數類型

import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
import java.util.Collection;

public class ProxyCollection {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Class clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),
				Collection.class);
		// System.out.println(clazz.getName());
		// 現在想列印出所有的構造函數,并且如果是有參構造函數,就讓他帶上參數類型
		StringBuilder sb = new StringBuilder();
		Constructor[] constructors = clazz.getConstructors();
		for (Constructor constructor : constructors) {
			sb.append(constructor.getName());
			sb.append('(');
			Class[] clazzs = constructor.getParameterTypes();
			for (Class clazz1 : clazzs) {
				sb.append(clazz1.getName()).append(',');
			}
			if (clazzs != null && clazzs.length != 0) {
				sb.deleteCharAt(sb.length() - 1);
			}
			sb.append(')');
			System.out.println(sb);
		}

	}

}
           

列印結果:

黑馬程式員-代理

可是我有個問題,這樣做明顯更簡單,而且可以實作相同效果:

public static void main(String[] args) {
		// TODO Auto-generated method stub
		Class clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),
				Collection.class);
		// System.out.println(clazz.getName());
		// 現在想列印出所有的構造函數,并且如果是有參構造函數,就讓他帶上參數類型
		StringBuilder sb = new StringBuilder();
		Constructor[] constructors = clazz.getConstructors();
		for (Constructor constructor : constructors) {
			sb.append(constructor);
			System.out.println(sb);
		}

	}
           

列印結果:

黑馬程式員-代理

現在把構造函數換成普通方法試試:

public static void main(String[] args) {
		// TODO Auto-generated method stub
		Class clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),
				Collection.class);
		// System.out.println(clazz.getName());
		// 現在想列印出所有的構造函數,并且如果是有參構造函數,就讓他帶上參數類型
		StringBuilder sb = new StringBuilder();
		Method[] methods = clazz.getMethods();
		for (Method method : methods) {
			sb.append(method);
			sb.append("\n");
		}
		System.out.println(sb);

	}
           

列印結果:

黑馬程式員-代理

再用老師的方法試試:

public static void main(String[] args) {
		// TODO Auto-generated method stub
		Class clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),
				Collection.class);
		// System.out.println(clazz.getName());
		// 現在想列印出所有的構造函數,并且如果是有參構造函數,就讓他帶上參數類型
		StringBuilder sb = new StringBuilder();
		Method[] methods = clazz.getMethods();
		for (Method method : methods) {
			// sb.append(method);
			sb.append(method.getName());
			sb.append('(');
			Class[] clazzs = method.getParameterTypes();
			for (Class clazz1 : clazzs) {
				sb.append(clazz1.getName()).append(',');
			}
			if (clazzs != null && clazzs.length != 0) {
				sb.deleteCharAt(sb.length() - 1);
			}
			sb.append(')');
			sb.append("\n");
		}
		System.out.println(sb);

	}
           

列印結果:

黑馬程式員-代理

利用動态代理建立對象:

public class ProxyCollection {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		Class clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),
				Collection.class);
		Constructor constructor = clazz.getConstructor(InvocationHandler.class);
		class MyInvocationHandle implements InvocationHandler {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				// TODO Auto-generated method stub
				return null;
			}
		}
		Collection collection = (Collection) constructor
				.newInstance(new MyInvocationHandle());
		System.out.println(collection);
	}
}
           

但是用這種方式建立的時候,感覺必須先提前知道構造函數的類型和個數。

代理詳見:http://blog.csdn.net/caoyinghui1986/article/details/2450221  感覺講的還不錯,可以看看。

下面以Collection接口為列來進一步加強對動态代理的了解。

黑馬程式員-代理

調用coll.clear()方法時,正常運作,調用add()方法時,報錯,通過以上就可了解它為什麼會報錯,invoke()方法的傳回值為null,它的傳回值就是調用add()方法的傳回值,add()方法本來是要傳回boolean型資料的,但是現在傳回的卻是null,顯然,null是不能轉換為boolean型的。

現在我們寫一種較為簡單的方法:

Collection coll = (Collection) Proxy.newProxyInstance(
				Collection.class.getClassLoader(),
				new Class[] { Collection.class }, new InvocationHandler() {

					@Override
					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						// TODO Auto-generated method stub
						return null;
					}
				});
           

繼續修改代碼:

黑馬程式員-代理

一般代理類在代理時,需要執行一些額外的方法,一般把這些方法定義成一個對象,而且,要被代理的類也不能用寫死寫死。

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;

public class ProxyCollection1 {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		final ArrayList list = new ArrayList();
		Advice advice = new Actrual();
		Object coll = proxy(list, advice);
		coll.toString();

	}

	public static Object proxy(final Object target, final Advice advice) {
		Object coll = (Object) Proxy.newProxyInstance(target.getClass()
				.getClassLoader(), target.getClass().getInterfaces(),
				new InvocationHandler() {

					@Override
					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						// TODO Auto-generated method stub
						// 這兒一般要做一些工作,對于這些要做的事情,我們一般把這些方法封裝到一個類中,但是,我們怎麼知道這個類
						// 中又哪兒方法,不知道有如何調用?是以我們要定義一個接口,這個類必須實作該接口
						advice.beforeRun();
						Object obj = method.invoke(target, args);
						// 這兒也要做一些工作
						advice.afterRun();
						return obj;
					}
				});
		return coll;
	}

}
           

Advice 接口

public interface Advice {
	void beforeRun();

	void afterRun();

}
           

Actrual 類

public class Actrual implements Advice {

	@Override
	public void beforeRun() {
		// TODO Auto-generated method stub
		System.out.println("方法執行之前");
	}

	@Override
	public void afterRun() {
		// TODO Auto-generated method stub
		System.out.println("方法執行之後");
	}

}
           

實作AOP(面向方面程式設計)功能的封裝與配置

原理:

黑馬程式員-代理

哎,困難查重,終于做完,隻是大概了解,後面還的好好看看,以下是代碼:

BeanFactory類

package Spring;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class BeanFactory {
	InputStream ins;

	Properties prop = new Properties();

	public BeanFactory(InputStream ins) {
		this.ins = ins;
	}

	public Object getBean(String str) {

		Object obj = null;
		try {
			prop.load(ins);
			String str1 = prop.getProperty(str);

			obj = Class.forName(str1).newInstance();
			if (obj instanceof ProxyBeanFactory) {
				Advice advice = (Advice) Class.forName(
						prop.getProperty("xxx" + ".advice")).newInstance();
				Object target = Class.forName(
						prop.getProperty("xxx" + ".target")).newInstance();
				Object proxy = ((ProxyBeanFactory) obj)
						.getProxy(target, advice);
				return proxy;
			}
		} catch (Exception e) {
		}

		return obj;
	}

}
           

ProxyBeanFactory 類

package Spring;

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

public class ProxyBeanFactory {
	public Object getProxy(final Object target, final Advice advice) {
		Object coll = (Object) Proxy.newProxyInstance(target.getClass()
				.getClassLoader(), target.getClass().getInterfaces(),
				new InvocationHandler() {

					@Override
					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						// TODO Auto-generated method stub
						// 這兒一般要做一些工作,對于這些要做的事情,我們一般把這些方法封裝到一個類中,但是,我們怎麼知道這個類
						// 中又哪兒方法,不知道有如何調用?是以我們要定義一個接口,這個類必須實作該接口
						advice.beforeRun();
						Object obj = method.invoke(target, args);
						// 這兒也要做一些工作
						advice.afterRun();
						return obj;
					}
				});
		return coll;
	}

}
           

Config.properties 配置檔案

xxx=java.util.ArrayList
#xxx=Spring.ProxyBeanFactory
xxx.advice=Spring.Actrual
xxx.target=java.util.ArrayList
           

Advice 類

package Spring;

public interface Advice {
	void beforeRun();

	void afterRun();

}
           

Actrual 類

package Spring;

public class Actrual implements Advice {

	@Override
	public void beforeRun() {
		// TODO Auto-generated method stub
		System.out.println("方法執行之前");
	}

	@Override
	public void afterRun() {
		// TODO Auto-generated method stub
		System.out.println("方法執行之後");
	}

}
           

AppFrameworkTest 類

package Spring;

import java.io.FileInputStream;
import java.io.InputStream;

public class AppFramworkTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		InputStream ins = new FileInputStream("config.properties");
		BeanFactory bf = new BeanFactory(ins);
		Object obj = bf.getBean("xxx");
		System.out.println(obj.getClass().getName());

	}

}
           

---------------------- <a href="http://www.itheima.com" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="blank">ASP.Net+Unity開發</a>、<a href="http://www.itheima.com" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="blank">.Net教育訓練</a>、期待與您交流! ---------------------