java动态代理

代理模式:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

静态代理主要是通过继承来实现,若需要多个代理就会生成多个代理类,这样会导致类的急剧增多。动态代理可以解决静态代理的缺陷,可以对任意接口或方法生成任意的代理类,对被代理的对象和接口方法都能灵活的访问控制。

 

下面我们主要看看jdk中动态代理的实现方式:

Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:

(1). Interface InvocationHandler:该接口中仅定义了一个方法Object:

invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为方法的参数数组。

 

2).Proxy:该类即为动态代理类,其中主要包含以下内容:

Protected Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用。


所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

 

动态代理代码实现步骤:

1.创建一个handler类实现invocationHandler接口,实现invoke方法,handler类构造函数中包括目标对象的引用。

2.创建被代理的对象类和接口。

3.客户端调用类中通过调用newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)返回一个代理类实例,该实例调用目标对象的方法。

 

下面看一个实例:

 目标对象接口和实现类:

package com.proxy;

public interface Hello {
	
	void sayHello(String str);
}

package com.proxy;

public class HelloImpl implements Hello{

	@Override
	public void sayHello(String str) {
		  
		  System.out.println("hello: " +str);  
	}
}

日志处理handler:
package com.proxy;

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

/**
 * @Title:     LogHandler.java 
 * @Package:   com.proxy 
 * @Desc:      日志处理Handler
 * @Copyright: AsiaInfo-Linkage
 * @author:    gaoyb 
 * @date:      Mar 12, 2013 3:33:06 PM 
 * @Email:     gaoyb3@asiainfo-linkage.com
 */
public class LogHandler implements InvocationHandler{

	//定义目标对象类引用
	private Object obj = null;
	
	public LogHandler(Object realSubject) {
		this.obj = realSubject;
	}
	
	/*
	 * 动态代理类$Proxy0在调用被代理类的sayHello()方法时,会调用自己的sayHello()方法,而自己的sayHello()方法里会调用super.h.invoke(this, , ),
	 * super.h 也就是父类构造函数中的InvocationHandler h,这里的h就是我们的LogHandler对象。
	 * protected Proxy(InvocationHandler h) {
	      this.h = h;
       }
       
       所以调用sayHello()的请求就会被转发到LogHandler的invoke方法中,该invoke方法中 m.invoke(obj, args);会去调用obj对象的m中的方法。
	 */
	@Override
	public Object invoke(Object proxy, Method m, Object[] args)
			throws Throwable {
		  
		System.out.println("proxy class:"+proxy.getClass().getName());
		doBefore();
		
		//这里可以插入其他动作处理
		
		Object res = m.invoke(obj, args);
		
		//这里可以插入其他动作处理
		
		doAfter();
		
		//这里可以插入其他动作处理
		
		return res;
	}

	private void doBefore(){
		System.out.println("before log: do something....");
	}
	
	private void doAfter(){
		System.out.println("after log: do something....");
	}

 

客户端调用:

package com.proxy;

import java.lang.reflect.Proxy;

public class Client {

	
	public static void main(String args[]){
		
		HelloImpl impl = new HelloImpl();//被代理的对象
		LogHandler handler = new LogHandler(impl);
		
		/* 下面代码具体做了什么呢?。。。。
		 * 
		 * impl.getClass().getClassLoader():获得被代理类的类加载器
		 * impl.getClass().getInterfaces():获得被代理类实现的所有接口(这里只有一个Hello接口)
		 * handler:就是用于执行除了被代理接口中方法之外的用户自定义的额外操作,它也是用户需要代理的最终目的。
		 *
		 * 第一步:通过为 Proxy类指定 ClassLoader对象和一组interface来创建动态代理类$Proxy0:
		 *        Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces) 根据上面两个参数生成代理类$Proxy0的Class对象。
		 * 		  同时这个动态生成的$Proxy0类实现了要代理类的实现的所有接口,并继承了java.lang.reflect.Proxy类($Proxy0 extends Proxy implements Hello)。
		 *
		 * 第二步:通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型InvocationHandler h:
		 *        实例化这个动态生成的$Proxy0类的一个实例,实例化代理类的构造函数为Proxy(InvocationHandler h), 
         *        也就是说要实例化这个动态生成的$Proxy0类,必须给它一个InvocationHandler参数,也就是我们自己实现的用来在被代理类方法执行前后做额外工作的handler类(LogHandler) 
		 *        Constructor cons = cl.getConstructor(constructorParams);
	     *		  return (Object) cons.newInstance(new Object[] { h });
	     *
	     * 第三步:将这个$Proxy0类强制转型成被代理类接口类型(Hello),调用被代理类的方法sayHello()。
		 */
		Hello proxy = (Hello)Proxy.newProxyInstance(impl.getClass().getClassLoader(), 
				impl.getClass().getInterfaces(), handler);
		
		proxy.sayHello("dynamic proxy....");
	
	}
}


 结果:

proxy class:$Proxy0
before log: do something....
hello: dynamic proxy....
after log: do something....

 

 动态代理主要在日志、事务、权限、拦截器等切面操作中上使用,在spring Aop中有比较好的使用,大家不妨去研究研究。

 


 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值