首页 > 代码库 > 代理模式(静态代理+动态代理)——JAVA

代理模式(静态代理+动态代理)——JAVA

        代理模式是常用的java设计模式,他的特征是代理类与目标类有同样的接口,代理类主要负责为目标类预处理消息、过滤消息、把消息转发给目标类,以及事后处理消息等。代理类与目标类之间通常会存在关联关系,一个代理类的对象与一个目标类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用目标类的对象的相关方法,来提供特定的服务。

        结构图如下:

               

        按照代理的创建时期,代理类可以分为静态代理和动态代理。 
        静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类(Proxy)的.class文件就已经存在了。 

        动态代理:在程序运行时,运用反射机制动态创建代理类(Proxy)而成。

静态代理:

调用过程如下:
            
实例:
UserManager接口
package ZhuDan.Test;

public interface UserManager {
	public void addUser(String UserId,String UserName);
	public void queryUser(String UserId);
}
UserManagerImpl目标类实现UserManager接口:
package ZhuDan.Test;

public class UserManagerImpl implements UserManager {
	
	public void addUser(String UserId,String UserName) {
		System.out.println("用户ID:"+UserId);
		System.out.println("用户名:"+UserName);
	}

	public void queryUser(String UserId){
		System.out.println("用户ID:"+UserId);	
	}
}
UserManagerImplProxy代理类实现UserManager接口:
package ZhuDan.Test;

public class UserManagerImplProxy implements UserManager {

	private UserManager userManager;
	public UserManagerImplProxy(UserManager userManager){
		this.userManager=userManager;
	}
	public void addUser(String UserId,String UserName) {
		try{
			System.out.println("~~~~~~~~~~addUser开始执行~~~~~~~~~~~");
			userManager.addUser( UserId,UserName);
		}catch(Exception e){
			e.printStackTrace();
			System.out.print("~~~~~~~~~~addUser执行出错~~~~~~~~~~~");
		}finally{
			System.out.print("~~~~~~~~~~addUser成功执行~~~~~~~~~~~");
		}
	}
	
	public void queryUser(String UserId){
		try{
			System.out.println("~~~~~~~~~~queryUser开始执行~~~~~~~~~~~");
			userManager.queryUser( UserId);
		}catch(Exception e){
			e.printStackTrace();
			System.out.print("~~~~~~~~~~queryUser执行出错~~~~~~~~~~~");
		}finally{
			System.out.print("~~~~~~~~~~queryUser成功执行~~~~~~~~~~~");
		}
	}
}
Manager类:
package ZhuDan.Test;

public class Manager {
	public static void  main(String args[]){
		UserManager userManager=new UserManagerImplProxy(new UserManagerImpl());
		userManager.addUser("0001", "张三");
		userManager.queryUser("0001");
	}
}
打印结果:
        
分析静态代理:
      从上面的例子可以看到,每个代理类都只能为一个接口服务,这样一来,进行程序开发时必定会产生大量的类,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,这样就有很多的重复性代码。那么应该如何解决这个问题呢?这一问题最好的解决方式是可以通过一个代理类来完成全部的代理功能,这也就是动态代理。

动态代理:

流程图如下:
       
UserManager接口:
package ZhuDan.Test;

public interface UserManager {
	public void FindUserById(String UserId);
	public void addUser(String UserId,String UserName);
}
UserManagerImpl目标类实现UserManager接口:
package ZhuDan.Test;

public class UserManagerImpl implements UserManager {
	
	public void addUser(String UserId,String UserName) {
		System.out.println("用户ID:"+UserId);
		System.out.println("用户名:"+UserName);
	}

	public void FindUserById(String UserId){
		System.out.println("用户ID:"+UserId);	
	}
}
UserManagerImplProxy代理类实现InvocationHandler接口:
package ZhuDan.Test1;

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

public class UserManageProxy implements InvocationHandler {

	private Object target;  
    /** 
     * 绑定委托对象并返回一个代理类 
     * @param target 
     * @return 
     */  
    public Object bind(Object target) {  
    	//目标
        this.target = target;  
        ClassLoader str= target.getClass().getClassLoader();
        //取得代理对象   
        //newProxyInstance三个参数:代理类的装载器、接口、指派方法调用的调用处理程序
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
                target.getClass().getInterfaces(), this);    
    }  
	//args:包装所有参数
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		 	Object result=null;  
		 	System.out.println("~~~~~~~~~~"+method.getName()+" 开始执行~~~~~~~~~~~");
	        //取得参数
		 	for(int i=0;i<args.length;i++){
		 		System.out.println("《~~~~~~~~~~参数为:"+args[i]+"~~~~~~~~~~~》");
		 	}
		 	try{
			 	//执行方法  ,添加方法就是target,args是参数
		        result=method.invoke(target, args);  
		        System.out.println("~~~~~~~~~~"+method.getName()+" 成功执行~~~~~~~~~~~");
		 	}catch(Exception e){
		 		e.printStackTrace();
		 		System.out.print("~~~~~~~~~~"+method.getName()+"执行出错~~~~~~~~~~~");
		 	}
	        return result;  
	}
}
Manager类:
package ZhuDan.Test1;

public class Manager {
	public static void  main(String args[]){
		UserManageProxy userManagerProxy=new UserManageProxy();
		UserManager userManager=(UserManager)userManagerProxy.bind(new UserManagerImpl());
		userManager.FindUserById("0001");
		userManager.addUser("0001", "张三");
	}
}
输出结果:
       
分析:
         动态代理的实现包含一个类和一个接口: 
 InvocationHandler接口: 
        public interface InvocationHandler { 
               public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 
         } 
       参数说明: 
              Object proxy:指被代理的对象。 
              Method method:要调用的方法 
              Object[] args:方法调用时所含的参数 
Proxy类: 
         Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,提供了如下的操作方法: 
         public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h) throws IllegalArgumentException 
         参数说明: 
                 ClassLoader loader:类加载器,代理类和目标类为同一个加载器。
                 Class<?>[] interfaces:得到目标类的所有接口 
                 InvocationHandler h:得到InvocationHandler接口的子类实例,即代理类(UserManagerImplProxy

总结:

        动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类,而java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。