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);
	}
}

 

 

 

原文地址:https://www.cnblogs.com/chunguang-yao/p/10666404.html