---------------------- <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>、期待與您交流! ---------------------