java之动态代理

 一、代理模式简介(这里是转载别人的博客):

https://www.cnblogs.com/gonjan-blog/p/6685611.html

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预

处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联

关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用

委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象

来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性可以附加多种用途。

 

二、今天讲的是动态代理模式:

动态代理就是通过代理类是代理类与相关接口不直接发生联系,而在运行期(Runtime)实现动态关联。

首先先回顾一下类反射:

举例: 有一个接口如下:

public interface IRenter {
    public abstract void rent();
}

一个实现类:

package cn.hncu.proxy;

public class Renter implements IRenter {

	@Override
	public void rent() {
		System.out.println("真正的房东, 提供房子,收房租");	
	}
 
	public double aa(int n,double d){
		double s=0;
		if(n%2==1){
			s=n*3*d;
		}else{
			s=n*n*d;
		}
		return s;
	}
}

通过类反射:用类反射实现类似下面这样的功能:Renter r = new Renter();double s = r.aa(87,3.14);

1 先获取所要执行函数的method对象--m

2再执行m函数---当然得给它传实参和调用对象

//复习一下类反射
		@Test
		public void demo1() throws Exception{
			/*用类反射实现类似下面这样的功能: 
			   Renter r = new Renter();
			   double s = r.aa(87,3.14); 
			 */
			//1 先获取所要执行函数的method对象--m
			Class c=Renter.class;
			Class paramTypes[]={int.class,double.class};
			Method m = c.getMethod("aa", paramTypes);
			
			//2再执行m函数---当然得给它传实参和调用对象
			Object r=c.newInstance();// Object r = new Renter();
			Object args[]= {87,3.14};
			Object s=m.invoke(r, args);//※※※※  //double s = r.aa(87,3.14);
			System.out.println("s="+s);
			
		}

动态代理主要用到java.lang.reflect包中的两个类,InvocationHandler接口和Proxy类。

动态代理相较于静态代理最大的不同就是:动态代理的代理类不需要手动生成,

该代理类是在运行期间动态生成的,这个动态生成的代理类已经实现代理对象的

相关接口(Interface)。在生成代理类的同时,

必须提供一个handler,这个handler有InvocationHandler提供,

同时用来接管实际的工作。

 

动态代理, 技术入口: java.lang.reflect包中,

Object proxiedObj=Proxy.newProxyInstance(loader, interfaces, h)

1.loader即当前类的加载器:假设我们当前的类是ProxyDemo:那么loader=ProxyDemo.class.getClassLoader(),

2.interfaces即InvocationHandler接口 :

每一个动态代理类都必须实现InvocationHandler接口,InvocationHandler是代理实例(代理的真实对象),的调用处理程序实现的

接口,当通过代理实例调用一个方法的时候,该方法的调用就会指派到它调用处理程序(InvocationHandler接口)的 invoke

方法。

那上面的例子那么这里就是:

r.getClass().getInterfaces(), 
//new Class[]{IRenter.class}, //和上一句一样

3.invoke方法声明:

h即是invoke方法 也是监听要代理的方法:

回调函数,通过代理后的对象执行的所有方法(接口中有的)都会自动进入这个方法来实现"所调方法的功能

Object returnValue=method.invoke(r, args);//放行,即执行所代理对象原来的方法,

按上面的例子即是rent()方法

new InvocationHandler() {
						
@Override//回调函数,通过代理后的对象执行的所有方法(接口中有的)都会自动进入这个方法来实现"所调方法的功能"
public Object invoke(Object proxy, Method method, Object[] args)
	throws Throwable { //proxy即是proxiedObj
	System.out.println("前面拦拦,做些事情如收代理费.....");
        Object returnValue=method.invoke(r, args);//放行
        System.out.println("后面拦拦,做些事情如发个卡片,留个电话...");
	return returnValue;
       
 //return method.invoke(r, args); //简单放行
}
});

综上所述;代码如下;

@Test
		public void demo2() throws Exception{
			final Renter r=new Renter();
			
			Object proxiedObj=Proxy.newProxyInstance(
					ProxyDemo.class.getClassLoader(), 
					r.getClass().getInterfaces(), 
					 //new Class[]{IRenter.class}, //和一句一样
					new InvocationHandler() {
						
						@Override
						public Object invoke(Object proxy, Method method, Object[] args)
								throws Throwable { //proxy即是proxiedObj
							System.out.println("前面拦拦,做些事情如收代理费.....");
							Object returnValue=method.invoke(r, args);//放行
							System.out.println("后面拦拦,做些事情如发个卡片,留个电话...");
							return returnValue;
						

							//return method.invoke(r, args); //简单放行
						}
					});
			
			IRenter ir=(IRenter) proxiedObj;
			ir.rent();
		}
		

结果;

 

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类(JDK). Proxy类根据

提供的相关接口和被代理的类就可以利用反射机制得到实现的方法,根据Proxy类的newProxyInstance(...)方法生成代理类。

即技术入口:Object proxiedObj=Proxy.newProxyInstance(loader, interfaces, h)

假设这里需求是要代理一下list:

		//代理一下List list = new ArrayList();
		@Test
		public void demo3() throws Exception{
			Object proxyObj=Proxy.newProxyInstance(
					ProxyDemo.class.getClassLoader(),
					new Class[]{List.class}, 
					new MyInvocation());
			List list=(List) proxyObj;
			list.add("hncu");
			list.add(12);
			list.add(3.14);

			int len = list.size();
			for(int i=0; i<len; i++){
				System.out.println(list.get(i));
			}
		 }
}
		
class MyInvocation implements InvocationHandler{
	 
	final List srcList=new ArrayList();//原型对象
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		if(args==null || args.length==0){
			System.out.println("进来了,,你正在调用"+method.getName()+",空参");
		}else{
			System.out.println("进来了,,你正在调用"+method.getName()+",参数1是:"+args[0]);
		}
		return method.invoke(srcList, args); //放行
	}
			
}

 

下面写一个动态代理的工具类,也是以后会经常用到的工具类:

同样用一些简单的类做实例:

两个接口(这里为了方便放一起):

public interface IAnimal {
	public void run();
}

public interface IPerson {
	public void sayHi();
}

两个实现类

public class Person implements IPerson {

	private String name;
	
	public Person(String name) {
		this.name = name;
	}

	@Override
	public void sayHi() {
		System.out.println("您好,我叫"+name);
	}
   
}


public class Dog implements IAnimal {

	 private String name;
	 
	 
	public Dog(String name) {
		
		this.name = name;
	}


	@Override
	public void run() {
		System.out.println("小狗"+name+"正在跑...");
	}
   
}

 

真正的工具类:

个人认为这里最巧妙的思想也是经常会被忘记的地方:还是构造传参...

通过构造传参,即拿到原型对象,不同类传进来的是什么对象就是什么对象

package cn.hncu.proxy.utils;

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

public class ProxyUtils implements InvocationHandler {
	private Object srcObj;

	public ProxyUtils(Object srcObj) {
		super();
		this.srcObj = srcObj;
	}

	public static Object getProxy(Object srcObj) {
		Object proxiedObj = Proxy.newProxyInstance(ProxyUtils.class
				.getClassLoader(), srcObj.getClass().getInterfaces(),
				new ProxyUtils(srcObj));
		return proxiedObj;
	}

	@Override
	// 拦截动作
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("在通用代理工具中,前面拦拦...");
		Object returnValue = method.invoke(srcObj, args);
		// 放行
		System.out.println("在通用代理工具中,后面拦拦...");

		return returnValue;
	}

}

测试类:

package cn.hncu.proxy.utils;

import org.junit.Test;

public class UseProxyuUtils {
   
	@Test
	public void demo(){
		Dog dog = new Dog("小布丁");
		IAnimal dog2 =(IAnimal) ProxyUtils.getProxy(dog);
		dog2.run();
		
		IPerson p2 = (IPerson)  ProxyUtils.getProxy( new Person("张三") );
		p2.sayHi();
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值