黑马程序员------动态代理

---------------------- ASP.Net+Android+IO开发S.Net培训、期待与您交流! ---------------------- 

 

微笑动态代理

 

程序中的代理

为了可以在已经存在的多个具有相同接口的目标类的各个方法增加一些系统功能,如:异常处理、日志、计算方法的运行

时间、事物管理等。我们可以编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在

调用方法时加上系统功能的代码。

 

如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类还是代理类,

这样可以容易的切换。增加与移除系统功能灵活。

 

AOP

 

 

 动态代理技术:

 

1. 要为系统中各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式将会十分麻烦。

2.JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。

3.JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。

4.CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口

的类生成动态代理类,那么可以使用CGLIB库。

 

代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在以下的位置添加系统

功能代码:

a.在调用目标方法之前

b.在调用目标方法之后

c.在调用目标方法前后

d.在处理目标方法异常的catch块中

  

package com.lee.proxy;

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

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		Class clazzProxy1 = Proxy.getProxyClass(Collection.class
				.getClassLoader(), Collection.class);
		System.out.println(clazzProxy1);

		System.out.println("----------get constructors----------");
		// 得到代理类的所有构造方法
		Constructor[] constructors = clazzProxy1.getConstructors();
		for (Constructor constructor : constructors) {
			String name = constructor.getName();
			StringBuilder sb = new StringBuilder(name);
			sb.append('(');
			Class[] clazzParams = constructor.getParameterTypes();
			for (Class clazzParam : clazzParams) {
				sb.append(clazzParam.getName()).append(',');
			}
			if (clazzParams != null && clazzParams.length != 0)
				sb.deleteCharAt(sb.length() - 1);
			sb.append(')');
			System.out.println(sb);
		}

		System.out.println("----------get methods----------");
		// 得到所有代理类的方法以及参数类型
		Method[] methods = clazzProxy1.getMethods();
		for (Method method : methods) {
			String name = method.getName();
			StringBuilder sb = new StringBuilder(name);
			sb.append('(');
			Class[] clazzParams = method.getParameterTypes();
			for (Class clazzParam : clazzParams) {
				sb.append(clazzParam.getName()).append(',');
			}
			if (clazzParams != null && clazzParams.length != 0)
				sb.deleteCharAt(sb.length() - 1);
			sb.append(')');
			System.out.println(sb);
		}
		//得到代理类的构造方法。
		Constructor constructor = clazzProxy1
				.getConstructor(InvocationHandler.class);
		//实例化代理类,其中参数是个实现InvocationHandler()接口的对象
		Collection proxy1 = (Collection) constructor
				.newInstance(new InvocationHandler() {
					ArrayList arr = new ArrayList();

					@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(arr, args);
						long endTime = System.currentTimeMillis();
						System.out.println(method.getName() + ":"
								+ (endTime - beginTime));
						return retVal;
					}
				});
		proxy1.add("xyz");
		proxy1.add("lee");
		proxy1.add("com");
		System.out.println(proxy1.size());
	}
}

 

根据:

 

Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
        new Class[] { Foo.class },
        handler);


可以将代码进行再次优化

package com.lee.proxy;

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 ProxyDemo2 {
	//参数为目标对象,系统功能对象
	public static Object getProxy(final Object target, final Advice advice) {
		Object proxy = 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.beforeMethod(method);
						Object retVal = method.invoke(target, args);
						advice.afterMethod(method);
						return retVal;
					}
				});
		return proxy;
	}
	
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		//定义目标
		final ArrayList target = new ArrayList();
		//通过功能函数得到代理对象
		Collection proxy1 = (Collection) getProxy(target, new MyAdvice());

		proxy1.add("xyz");
		proxy1.add("lee");
		proxy1.add("com");
		System.out.println(proxy1.size());
	}

	
}
package com.lee.proxy;

import java.lang.reflect.Method;

public interface Advice {

	public void beforeMethod(Method method);
	
	public void afterMethod(Method method);
}
package com.lee.proxy;

import java.lang.reflect.Method;

public class MyAdvice implements Advice {

	long beginTime ;
	@Override
	public void afterMethod(Method method) {
		// TODO Auto-generated method stub
		long endTime = System.currentTimeMillis();
		System.out.println(method.getName() + ":" + (endTime - beginTime));
		System.out.println("功能结束了");
	}

	@Override
	public void beforeMethod(Method method) {
		// TODO Auto-generated method stub
		System.out.println("功能开始了");
		beginTime = System.currentTimeMillis();
	}

}


微笑实现AOP功能的封装与配置

 

工厂类BeanFctory负责创建目标类或代理类的实际对象,并通过配置文件实现切换。其中getBean方法根据参数

字符串返回一个相应的实例对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回

该类的实例对象否则,返回该类实例对象的getProxy方法返回的对象。

 

BeanFactory的构造方法接收代表配置文件的输入流对象,配置文件格式如下:

xxx=java.util.ArrayList
#xxx=com.lee.aopframwork.ProxyFactoryBean
xxx.advice=com.lee.proxy.MyAdvice
xxx.target=java.util.ArrayList

 

 

各方法的实现代码

 

BeanFactory.

package com.lee.aopframwork;

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

import com.lee.proxy.Advice;

public class BeanFactory {

	Properties prop = new Properties();
	//bean工厂的构造函数
	public  BeanFactory(InputStream ips) {
		try {
			prop.load(ips);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	//得到bean的函数
	public Object getBean(String name) {
		String className = prop.getProperty(name);
		Object bean = null;
		try {
			//System.out.println(className);
			Class clazz = Class.forName(className);
			bean = clazz.newInstance();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (bean instanceof ProxyFactoryBean) {
			Object proxy = null;
			ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) bean;
			try {
				Advice advice = (Advice)Class.forName(prop.getProperty(name+".advice")).newInstance();
				Object target = Class.forName(prop.getProperty(name+".target")).newInstance();
				proxyFactoryBean.setAdvice(advice);
				proxyFactoryBean.setTarget(target);
				proxy = proxyFactoryBean.getProxy();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} 
			return proxy;
		}
		return bean;
	}

}


ProxyFactoryBean

package com.lee.aopframwork;

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

import com.lee.proxy.Advice;

public class ProxyFactoryBean {

	private Advice advice;
	private Object target;

	public Advice getAdvice() {
		return advice;
	}

	public void setAdvice(Advice advice) {
		this.advice = advice;
	}

	public Object getTarget() {
		return target;
	}

	public void setTarget(Object target) {
		this.target = target;
	}

	public Object getProxy() {
		Object proxy = 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.beforeMethod(method);
						Object retVal = method.invoke(target, args);
						advice.afterMethod(method);
						return retVal;
					}
				});
		return proxy;
	}
}


AopFrameWorkTest

package com.lee.aopframwork;

import java.io.InputStream;

public class AopFrameWorkTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		InputStream ips = AopFrameWorkTest.class.getResourceAsStream("config.properties");
		Object bean = new BeanFactory(ips).getBean("xxx");
		System.out.println(bean.getClass().getName());
	}

}


 

 

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ---------------------- 

详情请查看:http://edu.csdn.net

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值