java语言代理模式

代理模式和JDK的动态代理技术学习笔记 01

            一直对jdk的动态代理技术认识很模糊,花了几天时间研究它的实现原理。本文章涉及到累的加载以及java反射机制方面的知识。如果对这两方面有一定的理解
的话会更加容易明白。

         代理模式:如果你学过或者知道装饰者模式,那么可以说你很容易就会掌握代理模式。
这两个模式很相似(个人的见解),都是通过传递一个需要被代理的对象(target)来
增强该类的功能。

  代理模式的的本质就是传递一个目标对象(target)的引用来进行目标对象的本身具有的操作,但是同时
代理类会在执行目标对象(target)本身具有的方法之前和之后添加一些额外的操作,以达到增强目标对象
(target)功能的目的。

  对于java语言来说,代理模式分为两种:1、静态代理;2、动态代理(目前主要包括JDK自身具备的动
态代理技术和cglib技术)

  静态代理很好理解,下面结合代码来讲述:


    先定义一个简单的接口:

package test.proxy;

    public interface BookFacade {

	//添加书本的方法
	void addBook();

    }

    然后就是这个接口的实现类:
package test.proxy;
    public class BookFacadeImpl implements BookFacade{
	@Override
	public void addBook() {

		System.out.println("添加书本");
		
	}	
    }


    然后就是这个接口某个实现类的代理类:
package test.proxy;
    public class BookFacadeProxy {
        //目标类的一个引用
	private BookFacade target;

	public BookFacadeProxy(BookFacade target){
	    
	    this.target=target;
	
	}

	public void addBook(){
	    System.out.println("==========添加操作之前=========");

            this.target.add();

	    System.out.println("==========添加操作之后=========");
	}
          
    }

    然后就是测试了:
<pre name="code" class="java"><span style="font-size:18px;"> package test.proxy;
    public class Main{

        BookFacade target=new BookFacadeImpl();
	BookFacadeProxy proxy=new BookFacadeProxy(target);
	proxy.addBook();

	}
    }</span>


 
 
执行测试之后的结果是:


    ==========添加操作之前=========
    添加操作
    ==========添加操作之后=========




    好了,这就是静态代理的一个基本应用。

   接下来就是讲JDK的动态代理技术了。
      动态代理技术主要是利用java.lang.reflect这个包的InvocationHandler接口和Proxy这两个类
  先通过一个例子来演示动态代理的用法和效果
     先定义一个接口:
 package dynamic.proxy;  
  
	/** 
	 * 目标对象实现的接口,用JDK来生成代理对象一定要实现一个接口 
	 * @author zyb 
	 * @since 2012-8-9 
	 * 
	 */  
	public interface UserService {  
	  
	    /** 
	     * 目标方法  
	     */  
	    public abstract void add();  
	  
	}  

         然后就是实现类:
package dynamic.proxy;   
  
	/** 
	 * 目标对象 
	 * @author zyb 
	 * @since 2012-8-9 
	 * 
	 */  
	public class UserServiceImpl implements UserService {  
	  
	    /* (non-Javadoc) 
	     * @see dynamic.proxy.UserService#add() 
	     */  
	    public void add() {  
		System.out.println("--------------------add---------------");  
	    }  
	}  

        接下来就是定义一个代理类:
package dynamic.proxy; 

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

	public class MyProxy implements InvocationHandler{

	     //目标对象的引用
	     private UserService target;

	     //构造方法传进一个UserService的实现类引用
	     public MyProxy(UserService target){
	         this.target=target;
	     }

	     //取得代理对象
	     public Object getMyProxy(){
	         return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),
		        this.target.getClass().getInterfaces(),this);
	     }

	     @Override
	     /*
	        proxy:代理类对象
		method:就是在这个参数所表示的方法的位置增强,和AOP思想中的横切点很相似(个人理解),
		         通过反射执行这个方法
		args:method执行所需要的参数。
	     */
	     public Object invoke(Object proxy,Method method,Object[] args) throws Exception{
	         //用于封装返回结果
		 Object result;

		 System.out.println("======执行add方法之前============");
                 result = method.invoke(target,args);
		 System.out.println("======执行add方法之后============");

		 return result;
	     }
	    
	}

       然后就是测试了:
package dynamic.proxy;
	public class Main{
		
		public static void main(String[] args) throws Exception{
			//先声明一个目标对象
		    UserService target=new UserServiceImpl();

	            //取得代理对象
		    UserService proxy = (UserService)new MyProxy(target).getMyProxy();

		    //使用代理对象执行添加操作
		    proxy.add();
			
		}
	    
	}

         输出结果如下:
======执行add方法之前============
        --------------------add---------------
======执行add方法之后============



     好了,通过上面的例子可以知道动态代理对目标对象的add方法进行了增强操作。
   但是从上面的例子也可以看出动态代理的局限性:需要和一个接口绑定在一起,只能针对
   一类接口增强
     其实可以将这个例子理解为一个简单的AOP实现。
   值得注意的是proxy并没有显示的执行MyProxy类的invoke()方法。但是达到了增强操作。
   了解下它背后进行的操作有助于我们更加好的动态代理技术,更好的运用它。


   现在通过代码来探究这个过程:
   将测试类Main改变下:
package dynamic.proxy;

	import java.lang.reflect.Field;
	import java.lang.reflect.Method;
	import java.lang.reflect.Proxy;
	public class Main{
		
		public static void main(String[] args) throws Exception{
			//制定被代理的对象
			UserService target=new UserServiceImpl();
			//取得代理对象
			UserService proxy=(UserService) new MyProxy(target).getMyProxy();
			
            //根据这里可以判断proxy是Proxy的子类,同时实现了UserService接口
			System.out.println(proxy instanceof Proxy);
			System.out.println(proxy instanceof UserService);
			System.out.println("==================================");
			
			//这里打印出这样的结果:proxy的类型是: class com.sun.proxy.$Proxy0
		    System.out.println("proxy的类型是: "+proxy.getClass().toString());
		    System.out.println("===================================");
		    
		    //这里通过反射技术取得proxy这个对象的信息来分析下proxy的结构
		    Class clazz=proxy.getClass();
		    
		    //属性
		    Field[] fields=clazz.getDeclaredFields();
		    System.out.println("proxy对象的属性有:");
		    for(Field f:fields){
		    	System.out.println(f.getName()+" , ");
		    }
		    System.out.println("==================================");
		    
		    //方法
		    Method[] method=clazz.getMethods();
		    System.out.println("proxy对象的方法有: ");
		    for(Method m:method){
		    	System.out.println(m.getName()+" , ");
		    }
		    System.out.println("===================================");
		    
		    //父类
		    System.out.println("proxy的父类: "+clazz.getSuperclass());
		    System.out.println("====================================");
		    
		    //接口
		    Class<?> interfaces[]=clazz.getInterfaces();
		    System.out.println("proxy实现的接口有: ");
		    for(Class<?> i:interfaces){
		    	System.out.println(i.getName()+" , ");
		    }
		    System.out.println("====================================");
		    
		    //运行结果
		    System.out.println("运行结果: ");
		    proxy.add();
		    
			
		}
	    

	}

接下来是控制台输出的结果:
true
true
==================================
proxy的类型是: class com.sun.proxy.$Proxy0
===================================
proxy对象的属性有:
m1 , 
m3 , 
m0 , 
m2 , 
==================================
proxy对象的方法有: 
add , 
equals , 
toString , 
hashCode , 
isProxyClass , 
getInvocationHandler , 
getProxyClass , 
newProxyInstance , 
wait , 
wait , 
wait , 
getClass , 
notify , 
notifyAll , 
===================================
proxy的父类: class java.lang.reflect.Proxy
====================================
proxy实现的接口有: 
dynamic.proxy.UserService , 
====================================
运行结果: 
======执行add方法之前============
--------------------add---------------
======执行add方法之后============

   
 从上面的输出结果我们可以得出下面的结论:


  1、proxy这个对象所对应的那个类的定义如下:
        public class $Proxy0 extends Proxy implements Uservice{
    //...............
}
  
  2、$Proxy0这个类并没有保存在我们的磁盘中。这个类是java虚拟机在执行代码
     期间根据需求动态创建出来的。java虚拟机创建$Proxy0这个类是直接生成字
     节码文件并且执行$Proxy0的对象proxy的相关方法来“隐式”执行了“增强操作”。


 分析到这里,可能还是会对动态代理的“隐式”执行操作是怎样进行的理解的不够清楚。
  接下来的第二篇来通过分析Proxy这个类和$Proxy0这个类的大概的源码来进一步讲解。
从更底层来理解jdk动态代理技术的实现。



































































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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值