---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"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">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ---------------------