基础加强_动态代理及AOP

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

动态代理及AOP

交叉业务的编程问题即为面向方面编程(Aspect oriented program ,简称AOP),AOP的目标就是要使交叉业务模块化。
代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术。

动态代理技术:CGLIB库

JVM可以在运行期动态生成类的字节码,这种动态生成的类往往被用作代理类,即动态代理类
JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。

代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码
1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法前后
4.在处理目标方法异常的catch块中

通过代码来看动态代理的工作原理及结构

定义Advice接口
import java.lang.reflect.Method;
//定义公共的接口,两个方法计算method方法的运行时间
public interface Advice {
	void beforeMethod(Method method);
	void afterMethod(Method method);
}
实现Advice接口
import java.lang.reflect.Method;


public class MyAdvice implements Advice {
	long beginTime = 0;
	public void afterMethod(Method method) {	
		long endTime = System.currentTimeMillis();
		System.out.println(method.getName() + " running time of " + (endTime - beginTime));
	}
	public void beforeMethod(Method method) {
		beginTime = System.currentTimeMillis();
	}
}
生成动态代理代码
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 {


	public static void main(String[] args) throws Exception{
		// 返回用指定的类加载器定义的代理类的Class对象,它可以实现指定的Collection接口 
		Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
		System.out.println(clazzProxy1.getName());//$Proxy0
		
		System.out.println("----------begin constructors list----------");


		//获取构造方法
		Constructor[] constructors = clazzProxy1.getConstructors();
		//以带参数的格式打印构造方法
		for(Constructor constructor : constructors){
			String name = constructor.getName();
			StringBuilder sBuilder = new StringBuilder(name);
			sBuilder.append('(');
			Class[] clazzParams = constructor.getParameterTypes();
			for(Class clazzParam : clazzParams){
				sBuilder.append(clazzParam.getName()).append(',');
			}
			if(clazzParams!=null && clazzParams.length != 0)
				sBuilder.deleteCharAt(sBuilder.length()-1);
			sBuilder.append(')');
			System.out.println(sBuilder.toString());	//只有一个$Proxy0(java.lang.reflect.InvocationHandler)		
		}


		System.out.println("----------begin methods list----------");
		/*$Proxy0()
		$Proxy0(InvocationHandler,int)*/
		//获取代理类的方法,并打印,结果显示是Collection类的方法
		Method[] methods = clazzProxy1.getDeclaredMethods();
		for(Method method : methods){
			String name = method.getName();
			StringBuilder sBuilder = new StringBuilder(name);
			sBuilder.append('(');
			Class[] clazzParams = method.getParameterTypes();
			for(Class clazzParam : clazzParams){
				sBuilder.append(clazzParam.getName()).append(',');
			}
			if(clazzParams!=null && clazzParams.length != 0)
				sBuilder.deleteCharAt(sBuilder.length()-1);
			sBuilder.append(')');
			System.out.println(sBuilder.toString());			
		}
		
		System.out.println("----------begin create instance object----------");
		//Object obj = clazzProxy1.newInstance(); 没有无参的构造方法,不能这样创建对象
		//获取代理类构造方法。
		Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
		
		//定义InvocationHandler局部内部类,实现invoke方法
		class MyInvocationHander1 implements InvocationHandler{
			public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
				return null;
			}		
		}
		//通过构造方法创建对象,传入MyInvocationHander1对象,因为知道是collection类,所以直接强制类型转换
		Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHander1());
		
		System.out.println(proxy1);//输出null,因为proxy1的toString方法被转发
		proxy1.clear();
//		proxy1.size();//调用带有返回值的方法出现空指针异常
		//匿名内部类的方式
		Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				return null;
			}			
		});
		
		final ArrayList target = new ArrayList();
		//抽取获取代理类方法getProxy(obj,advice),生成代理类对象
		Collection proxy3 = (Collection)getProxy(target,new MyAdvice());
		proxy3.add("zxx");
		proxy3.add("lhm");
		proxy3.add("bxd");
		System.out.println(proxy3.size());
		System.out.println(proxy3.getClass().getName());//$Proxy1
	}
	//生成代理类实例方法,接收代理目标对象,和advice两个参数
	private static Object getProxy(final Object target,final Advice advice) {
		//直接使用Proxy类的newProxyInstance方法创建代理类对象
		Object proxy3 = Proxy.newProxyInstance(
				target.getClass().getClassLoader(),	//参数一,ClassLoader
				target.getClass().getInterfaces(), //参数二,实现的接口数组
				new InvocationHandler(){  //参数三,InvacationHandler对象			
					public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {	
						//将advice定义为final类型,方法接收需要代理的方法名
						//在invoke方法前后添加功能代码
						advice.beforeMethod(method);
						//target为需要代理的接口
						Object retVal = method.invoke(target, args);
						advice.afterMethod(method);
						return retVal;												
					}
				}
				);
		return proxy3;
	}


}

代理方法转发
调用调用代理对象的从Object类继承的hashCode, equals, 或toString这几个方法时,
代理对象将调用请求转发给InvocationHandler对象,对于其他方法,则不转发调用请求。


代理用于为某个对象生成和返回其代理对象,源对象必须实现接口,生成的代理对象会实现与源对象相同的接口,
注意,源对象的类必须自己定义时就实现接口,从该类的祖辈类上继承的接口是无效的。
该方法接口两个参数:一个是目标对象,另一个是封装了用户系统功能代码的Advice对象,
该对象必须实现Advice接口



实现AOP功能的封装与配置
需求:
工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。其getBean方法根据参数字符串返回一个相应的实例对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则,返回该类实例对象的getProxy方法返回的对象。
BeanFactory的构造方法接收代表配置文件的输入流对象,
配置文件config.properties内容
#xxx=java.util.ArrayList
xxx=cn.itcast.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=cn.itcast.MyAdvice

ProxyFacotryBean充当封装生成动态代理的工厂,需要为工厂类提供哪些配置参数信息?
目标target
通知advice
编写客户端应用:
编写实现Advice接口的类和在配置文件中进行配置
调用BeanFactory获取对象
测试代码
import java.io.InputStream;
import java.util.Collection;


public class AopFrameworkTest {
	public static void main(String[] args) throws Exception {
		// 关联配置文件
		InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");
		// 根据配置信息生成Bean工厂对象并返回对象
		Object bean = new BeanFactory(ips).getBean("xxx");
		System.out.println(bean.getClass().getName());//$Proxy0 代理类
		((Collection)bean).clear();
	}
}

Bean工厂类代码
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;


import cn.itcast.day3.Advice;


public class BeanFactory {
	//通过构造方法关联配置文件,初始化配置文件
	Properties props = new Properties();
	public BeanFactory(InputStream ips){
		try {
			props.load(ips);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	//根据配置文件获取相应的对象
	public Object getBean(String name){
		String className = props.getProperty(name);
		Object bean = null;
		try {
			Class clazz = Class.forName(className);
			bean = clazz.newInstance();//获取对象的实例
		} catch (Exception e) {
			e.printStackTrace();
		} 
		if(bean instanceof ProxyFactoryBean){//如果对象时代理工厂类,则返回代理代理工厂对象
			Object proxy = null;
			ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;
			try {
				//代理需要advice和target,获取advice和target对象
				Advice advice = (Advice)Class.forName(props.getProperty(name + ".advice")).newInstance();
				Object target = Class.forName(props.getProperty(name + ".target")).newInstance();
				//设置代理工厂对象的配置信息
				proxyFactoryBean.setAdvice(advice);
				proxyFactoryBean.setTarget(target);
				//生成动态代理对象
				proxy = proxyFactoryBean.getProxy();
			} catch (Exception e) {
				e.printStackTrace();
			}
			return proxy;
		}
		return bean;
	}
}

代理工厂
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


import cn.itcast.day3.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 proxy3 = Proxy.newProxyInstance(
				target.getClass().getClassLoader(),
				target.getClass().getInterfaces(),
				new InvocationHandler(){
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						advice.beforeMethod(method);
						Object retVal = method.invoke(target, args);
						advice.afterMethod(method);
						return retVal;						
					}
				}
				);
		return proxy3;
	}
}


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

你可能感兴趣的:(基础加强_动态代理及AOP)