zoukankan      html  css  js  c++  java
  • java动态代理

    动态代理的特点:

    字节码随用随创建,随用随加载。

    它与静态代理的区别也在于此。因为静态代理是字节码一上来就创建好,并完成加载。

     装饰者模式就是静态代理的一种体现。

    动态代理常用的有两种方式

    基于接口的动态代理

    提供者:JDK官方的Proxy类。

    要求:被代理类最少实现一个接口。

    基于子类的动态代理

    提供者:第三方的CGLib,如果报asmxxxx异常,需要导入asm.jar。

    要求:被代理类不能用final修饰的类(最终类)。

    使用JDK官方的Proxy类创建代理对象

    此处我们使用的是一个演员的例子:

              在很久以前,演员和剧组都是直接见面联系的。没有中间人环节。

              而随着时间的推移,产生了一个新兴职业:经纪人(中间人),这个时候剧组再想找演员就需要通过经纪人来找了。下面我们就用代码演示出来。

    /**
     * 一个经纪公司的要求:
     * 		能做基本的表演和危险的表演
    */
    public interface IActor {
    	/**
    	 * 基本演出
    	 * @param money
    	 */
    	public void basicAct(float money);
    	/**
    	 * 危险演出
    	 * @param money
    	 */
    	public void dangerAct(float money);
    }
    
    /**
     * 一个演员
     */
    //实现了接口,就表示具有接口中的方法实现。即:符合经纪公司的要求
    public class Actor implements IActor{
    	
    	public void basicAct(float money){
    		System.out.println("拿到钱,开始基本的表演:"+money);
    	}
    	
    	public void dangerAct(float money){
    		System.out.println("拿到钱,开始危险的表演:"+money);
    	}
    }
    
    public class Client {
    	
    	public static void main(String[] args) {
    		//一个剧组找演员:
    		final Actor actor = new Actor();//直接
    		
    		/**
    		 * 代理:
    		 * 	间接。
    		 * 获取代理对象:
    		 * 	要求:
    		 * 	 被代理类最少实现一个接口
    		 * 创建的方式
    		 *   Proxy.newProxyInstance(三个参数)
    		 * 参数含义:
    		 * 	ClassLoader:和被代理对象使用相同的类加载器。
    		 *  Interfaces:和被代理对象具有相同的行为。实现相同的接口。
    		 *  InvocationHandler:如何代理。
    		 *  		策略模式:使用场景是:
    		 *  					数据有了,目的明确。
    		 *  					如何达成目标,就是策略。
    		 *  			
    		 */
    		IActor proxyActor = (IActor) Proxy.newProxyInstance(
    										actor.getClass().getClassLoader(), 
    										actor.getClass().getInterfaces(), 
    										new InvocationHandler() {
    				/**
    				 * 执行被代理对象的任何方法,都会经过该方法。
    				 * 此方法有拦截的功能。
    				 * 
    				 * 参数:
    				 * 	proxy:代理对象的引用。不一定每次都用得到
    				 * 	method:当前执行的方法对象
    				 * 	args:执行方法所需的参数
    				 * 返回值:
    				 * 	当前执行方法的返回值
    				 */
    				@Override
    				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    					String name = method.getName();
    					Float money = (Float) args[0];
    					Object rtValue = null;
    					//每个经纪公司对不同演出收费不一样,此处开始判断
    					if("basicAct".equals(name)){
    						//基本演出,没有2000不演
    						if(money > 2000){
    							//看上去剧组是给了8000,实际到演员手里只有4000
    							//这就是我们没有修改原来basicAct方法源码,对方法进行了增强
    							rtValue = method.invoke(actor, money/2);
    						}
    					}
    					if("dangerAct".equals(name)){
    						//危险演出,没有5000不演
    						if(money > 5000){
    							//看上去剧组是给了50000,实际到演员手里只有25000
    							//这就是我们没有修改原来dangerAct方法源码,对方法进行了增强
    							rtValue = method.invoke(actor, money/2);
    						}
    					}
    					return rtValue;
    				}
    		});
    		//没有经纪公司的时候,直接找演员。
    //		actor.basicAct(1000f);
    //		actor.dangerAct(5000f);
    		
    		//剧组无法直接联系演员,而是由经纪公司找的演员
    		proxyActor.basicAct(8000f);
    		proxyActor.dangerAct(50000f);
    	}
    }
    

     

    使用CGLib的Enhancer类创建代理对象

    还是那个演员的例子,只不过不让他实现接口。

    /**
     * 一个演员
    */
    public class Actor{//没有实现任何接口
    	
    	public void basicAct(float money){
    		System.out.println("拿到钱,开始基本的表演:"+money);
    	}
    	
    	public void dangerAct(float money){
    		System.out.println("拿到钱,开始危险的表演:"+money);
    	}
    }
    
    public class Client {
    	/**
    	 * 基于子类的动态代理
    	 * 	要求:
    	 * 		被代理对象不能是最终类
    	 * 	用到的类:
    	 * 		Enhancer
    	 * 	用到的方法:
    	 * 		create(Class, Callback)
    	 * 	方法的参数:
    	 * 		Class:被代理对象的字节码
    	 * 		Callback:如何代理
    	 * @param args
    	 */
    	public static void  main(String[] args) {
    		final Actor actor = new Actor();
    		
    		Actor cglibActor = (Actor) Enhancer.create(actor.getClass(),
    							new MethodInterceptor() {
    			/**
    			 * 执行被代理对象的任何方法,都会经过该方法。在此方法内部就可以对被代理对象的任何方法进行增强。
    			 * 
    			 * 参数:
    			 * 	前三个和基于接口的动态代理是一样的。
    			 * 	MethodProxy:当前执行方法的代理对象。
    			 * 返回值:
    			 * 	当前执行方法的返回值
    			 */
    			@Override
    			public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    				String name = method.getName();
    				Float money = (Float) args[0];
    				Object rtValue = null;
    				if("basicAct".equals(name)){
    					//基本演出
    					if(money > 2000){
    						rtValue = method.invoke(actor, money/2);
    					}
    				}
    				if("dangerAct".equals(name)){
    					//危险演出
    					if(money > 5000){
    						rtValue = method.invoke(actor, money/2);
    					}
    				}
    				return rtValue;
    			}
    		});		
    		cglibActor.basicAct(10000);
    		cglibActor.dangerAct(100000);
    	}
    }
    

     

     

     

  • 相关阅读:
    Tree Constructe(icpc济南)(二分图+构造)
    Cleaning(CF1474D)
    Matrix Equation (2020icpc济南)
    关于位运算
    poj2540半平面交+判范围
    做题记录0(并查集|树状数组)
    ac自动机
    二次剩余
    BSGS算法
    无向图的桥
  • 原文地址:https://www.cnblogs.com/chunguang-yao/p/10666404.html
Copyright © 2011-2022 走看看