黑马程序员--java高新技术--动态代理

------- android培训java培训、期待与您交流! ---------

1.什么是代理?

一种用于转发请求,进行特殊处理的机制。“动态”指的是运行期。

2.为什么使用动态代理?

可以对请求进行任何处理

3.使用它有什么好处?

4.哪些地方需要动态代理?

不允许直接访问某些类,对访问要做特殊处理。




AOP面向方面的编程:

系统中存在许多交叉业务,一个交叉业务就是要切入到系统的一个方面。

同样的动作会在不同的模块中,这些动作就是模块的交叉业务。


可以把这些交叉业务都当做一个切面:



交叉业务的编程问题即为面向方面的编程(Aspect oriented program ,简称AOP),AOP的目标就是要使交叉业务模块化。可以采

用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的,如下所示:



使用代理技术可以解决aop的核心技术。

jvm可以在运行期动态生产出一个类,这种动态生成的类往往北用作代理,既动态代理。

动态类必须实现一个或多个接口。

CGLIB可以生成没有实现接口和类的动态代理。


package cn.jhc.day3;

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 ProxyTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
		//Proxy.getProxyClass(类加载器, 接口)
		Class classProxy1 = 
		        Proxy.getProxyClass(Collection.class.getClassLoader(),
		        		Collection.class);
		//System.out.println(classProxy1.getName());
		System.out.println("----begin constructors list ----");
		/*
		 * $Proxy0()
		 * $Proxy0(InvocationHandler,int)
		 * */
		//获取类的所有构造方法。
		Constructor[] constructors = classProxy1.getConstructors();
		for (Constructor constructor : constructors) {
			//得到构造方法名
			String name = constructor.getName();
			StringBuilder sBuilder = new StringBuilder(name);
			//性能比buffer高
			sBuilder.append('(');
			//得到构造方法的参数
			Class[] classParams = constructor.getParameterTypes();
			for (Class classParam : classParams) {
				sBuilder.append(classParam.getName()).append(',');
			}
			if(classParams.length != 0 && classParams != null)
			sBuilder.deleteCharAt(sBuilder.length()-1);
			
			sBuilder.append(')');
			System.out.println(sBuilder.toString());
		}
		System.out.println("----begin methods list ----");
		/*
		 * $Proxy0()
		 * $Proxy0(InvocationHandler,int)
		 * */
		//得到所有方法
		Method[] methods = classProxy1.getMethods();
		for (Method method : methods) {
			//得到方法名
			String name = method.getName();
			StringBuilder sBuilder = new StringBuilder(name);
			//性能比buffer高
			sBuilder.append('(');
			//得到方法的参数
			Class[] classParams = method.getParameterTypes();
			for (Class classParam : classParams) {
				sBuilder.append(classParam.getName()).append(',');
			}
			if(classParams.length != 0 && classParams != null)
			sBuilder.deleteCharAt(sBuilder.length()-1);
			
			sBuilder.append(')');
			System.out.println(sBuilder.toString());
		}
		System.out.println("----begin create instance object ----");		
		//classProxy1.newInstance();
		//得到构造方法
		Constructor constructor = classProxy1.getConstructor(InvocationHandler.class);
		//InvocationHandler是一个接口
//		class MyInvocationHandler1 implements InvocationHandler{
//
//			@Override
//			public Object invoke(Object proxy, Method method, Object[] args)
//					throws Throwable {
//				// TODO Auto-generated method stub
//				return null;
//			}
//			
//		}
//		Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHandler1());
//		System.out.println(proxy1);
//		proxy1.clear();
//		//proxy1.size();
//		
		//创建代理对象,创建匿名内部接口
		Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
			//实现接口的invoke方法。
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				// TODO Auto-generated method stub
				return null;
			}
			
		});
		final ArrayList target = new ArrayList();
		Collection proxy3 = (Collection)getProxy(target,new MyAdvice());
		proxy3.add("zxx");
		proxy3.add("bxd");
		proxy3.add("bad");
		System.out.println(proxy3.size());
	}

	private static Object getProxy(final Object target,final Advice advice) {
		Object proxy3 = Proxy.newProxyInstance(
					target.getClass().getClassLoader(),
//						new Class[]{Collection.class},
						target.getClass().getInterfaces(),
						new InvocationHandler(){
		
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						// TODO Auto-generated method stub
						
//						long beginTime = System.currentTimeMillis();
//						Object retVal = method.invoke(target, args);
//						long endTime = System.currentTimeMillis();
//						System.out.println(method.getName() + " running time of " + (endTime - beginTime));
//						return retVal;
						
						
						//在目标前实现自己的方法
						advice.beforeMethod(method);
						Object retVal = method.invoke(target, args);
						//在目标后实现自己的方法
						advice.afterMethod(method);
						
						
						return retVal;
					}
					
				});
		return proxy3;
	}

}


总结一下需要注意的地方:

目标方法要求返回的值类型与代理类返回的值类型应当保持一致;

newProxyInstance()方法可以得到一个动态代理类,它需要接受3个参数

public static Object newProxyInstance(ClassLoader loader, 

Class<?>[] interfaces, 

InvocationHandler h)

Loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载

Interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了

h一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

InvocationHandler中需要实现的invoke()方法接受三个参数

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

proxy: 指代我们所代理的那个真实对象

method: 指代的是我们所要调用真实对象的某个方法的Method对象

args: 指代的是调用真实对象某个方法时接受的参数

这个invoke方法要用到这些参数的原因是:代理类要去找目标类的方法并调用,然后返回。


------- android培训java培训、期待与您交流! ---------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值