黑马程序员-------(高新技术)代理

本文深入探讨Java动态代理机制,解析如何利用代理模式增强类的功能,包括在调用目标方法前后的增强逻辑,以及如何处理异常。并通过具体示例展示了如何创建代理对象并实现AOP功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

-------------java培训android培训、java博客、java学习型技术博客、期待与您交流! --------------

 

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

 

package cn.itcast.day3;

import java.lang.reflect.Method;

public interface Advice {
	/* 1.在调用目标方法之前
	 * 2.在调用目标方法之后
	 * 3.在调用目标方法前后
	 * 4.在处理目标方法异常的catch块中*/
	void beforeMethod(Method method);
	void afterMethod(Method method);
	
}


 

package cn.itcast.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 {

	public static void main(String[] args) throws Exception {

		Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class);
		System.out.println(clazzProxy1.getName());

		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);
		}
		
		System.out.println("----------begin methods list----------");
		Method[] methods = clazzProxy1.getMethods();
		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);
		}
		System.out.println("----------begin create instance object ----------");
		Constructor constructor = clazzProxy1.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;
			}
			
		}
		//InvocationHandler是个接口,自己做过实现类,然后传入。
		Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHandler1());
		//用匿名内部类方法创建对象
		Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){

			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				return null;
			}
			
		});
		
		//说明对象已经创建成功,但是返回值是null
		System.out.println(proxy1.toString());
		/*但是有返回值的方法无法调用
		 * 原因是:上面的InvocationHandler子类的invoke()方法返回值是null */		
		//proxy1.size();
		/*返回值为void的方法可以调用
		 *原因是:上面的InvocationHandler子类的invoke()方法返回值是null*/
		proxy1.clear();
		
		//抽取出来的target,内部类要直接访问外部类中的成员变量,必须被final修饰
		final ArrayList target = new ArrayList();
		Collection proxy3 = (Collection)getProxy(target,new MyAdvice());
		//程序调用proxy3.add("zxx");方法时,涉及三要素:proxy3对象、add方法、"zxx"参数
		proxy3.add("zxx");
		proxy3.add("lhm");
		Object proxy3retValue = proxy3.add("bxd");
		System.out.println("--------------proxy3.add(bxd);"+proxy3retValue);
		System.out.println(proxy3.size());
		
		System.out.println(proxy3.getClass().getName());
		
	}
	//修改成通用的,就要把返回值Collection改成Object
	private static Object getProxy(final Object target,final Advice advice) {
		//用Proxy.newInstance方法直接一步就创建出代理对象。
		
		Object proxy3 = Proxy.newProxyInstance(
		/*Collection proxy3 = (Collection)Proxy.newProxyInstance(*/ 
				
				target.getClass().getClassLoader(),
				/*Collection.class.getClassLoader(),*/
				
				target.getClass().getInterfaces(),
				/*new Class[]{Collection.class},*/ 
				
				//在InvocationHandler内部指定动态类的目标
				new InvocationHandler(){
					/*如果ArrayList target = new ArrayList();放在这里,
					 * ArrayList就是InvocationHandler子类的成员变量
					 * 结果就是 3。
					 * */
					//将ArrayList target = new ArrayList();抽取到外部类中,即内部类访问外部类
					//ArrayList target = new ArrayList();
					//					(  proxy3对象 ,        add方法,    "zxx"参数)
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						/*如果ArrayList target = new ArrayList();放在这里,
						 * proxy3.add("zxx");
						 * proxy3.add("lhm");
						 * proxy3.add("bxd");
						 * proxy3每次调用add()都会找InvocationHandler子类中的invoke()方法,
						 * 但是此时,每次都会新建一个new ArrayList();。
						 * proxy3.size()被调用也是新的ArrayList。
						 * 所以结果会是 0.				
						*/
						//ArrayList target = new ArrayList();
						
						
						/*long beginTime = System.currentTimeMillis();
						Object retValue = method.invoke(target, args);
						long endTime = System.currentTimeMillis();
						System.out
								.println(method.getName() + "running time of "
										+ (endTime - beginTime));*/
						

						advice.beforeMethod(method);
						Object retValue = method.invoke(target, args);
						advice.afterMethod(method);
						
						//打印true,表示proxy3.add("zxx");添加元素操作成功!!
						//System.out.println(retValue);
						return retValue;
						//如果这样写,就是在此调用,递归,死循环
						//return method.invoke(proxy, args);
					}	
				});
		return proxy3;
	}
}


运行结果

$Proxy0
----------begin constructors list----------
$Proxy0(java.lang.reflect.InvocationHandler)
----------begin methods list----------
add(java.lang.Object)
hashCode()
clear()
equals(java.lang.Object)
toString()
contains(java.lang.Object)
isEmpty()
addAll(java.util.Collection)
iterator()
size()
toArray([Ljava.lang.Object;)
toArray()
remove(java.lang.Object)
containsAll(java.util.Collection)
removeAll(java.util.Collection)
retainAll(java.util.Collection)
isProxyClass(java.lang.Class)
getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;)
newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler)
getInvocationHandler(java.lang.Object)
wait()
wait(long,int)
wait(long)
getClass()
notify()
notifyAll()
----------begin create instance object ----------
null
到传智播客学习啦!
addrunning time of 0
从传智播客毕业上班了!
到传智播客学习啦!
addrunning time of 0
从传智播客毕业上班了!
到传智播客学习啦!
addrunning time of 0
从传智播客毕业上班了!
--------------proxy3.add(bxd);true
到传智播客学习啦!
sizerunning time of 0
从传智播客毕业上班了!
3
$Proxy1


 

package cn.itcast.day3;

import java.lang.reflect.Method;

public class MyAdvice implements Advice {
	long beginTime=0;
	
	@Override
	public void beforeMethod(Method method) {
		System.out.println("到传智播客学习啦!");
		beginTime = System.currentTimeMillis();
	}
	@Override
	public void afterMethod(Method method) {
		
		long endTime = System.currentTimeMillis();
		System.out
				.println(method.getName() + "running time of "
						+ (endTime - beginTime));
		System.out.println("从传智播客毕业上班了!");
	}

	

}


 

实现AOP功能的封装与配置

工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。其getBean方法根据参数字符串返回一个相应的实例对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则,返回该类实例对象的getProxy方法返回的对象。
BeanFactory的构造方法接收代表配置文件的输入流对象,配置文件格式如下:
 #xxx=java.util.ArrayList
 xxx=cn.itcast.ProxyFactoryBean
 xxx.target=java.util.ArrayList
 xxx.advice=cn.itcast.MyAdvice
ProxyFacotryBean充当封装生成动态代理的工厂,需要为工厂类提供哪些配置参数信息?
目标
通知
编写客户端应用:
编写实现Advice接口的类和在配置文件中进行配置
调用BeanFactory获取对象

package cn.itcast.day3.aopframwork;

import java.io.InputStream;
import java.util.Collection;

public class AopFramworkTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//因为配置文件使用的是相对路径,所以配置文件要和AopFramworkTest在同一个目录下
		InputStream ips = AopFramworkTest.class.getResourceAsStream("config.properties");
		Object bean = new BeanFactory(ips).getBean("xxx");
		System.out.println(bean.getClass().getName());
	
		((Collection)bean).clear();
	
	}

	
}

运行结果

$Proxy0
到传智播客学习啦!
clearrunning time of 0
从传智播客毕业上班了!



 

package cn.itcast.day3.aopframwork;

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);
			//对已JavaBean类一定要有无参构造方法
			//原因:是clazz.newInstance();只有newInstance()的方法
			bean = clazz.newInstance();
		} catch (Exception e) {e.printStackTrace();}
		
		if(bean instanceof ProxyFactoryBean){
			Object proxy = null;
			ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;
			try {
				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;
	}
}


 

package cn.itcast.day3.aopframwork;

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 targer) {
		this.target = targer;
	}
	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 retValue = method.invoke(target, args);
						advice.afterMethod(method);
						return retValue;
					}	
				});
		return proxy3;
	}

}


config.properties配置文件内容

#xxx=java.util.ArrayList
xxx=cn.itcast.day3.aopframwork.ProxyFactoryBean
xxx.advice=cn.itcast.day3.MyAdvice
xxx.target=java.util.ArrayList

 

-------------java培训android培训、java博客、java学习型技术博客、期待与您交流! --------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值