黑马程序员-代理

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值