第一章 Java基础之JDK动态代理

          最近在找工作,许多面试官都比较喜欢问Spring AOP,

          面试官:Spring AOP的原理是什么?

          答:动态代理。

          面试官:动态代理的是怎么实现的?

          答:......................
          工资还想到12K,做梦吧!
          回去后鄙人痛定思痛,冥思苦想一朝悟得何为“动态代理”。各位道友请听我一一道来

          =========================================================================================================================

      何为代理?代理的作用是啥?

          代理就是A调用C不直接调用,中间会经过B来处理,也就是A通过B来调用C。代理的好处是控制对目标对象的访问,可以做到权限控制,还能做到功能的增强。

          何为动态代理?

          提到动态代理之前先说一下静态代理,静态代理就是在代码编译之前代理类已经写好了,就是已经存在Java源文件了;动态代理类是不需要你去手动书写Java源文件,是在程序运行的时候根据你所传参数生成的类生成相应的字节码,再通过字节码去创建代理对象。我们一般写代码就是如果想实现某个功能,就得新建一个java文件,在这个java文件中创建类,在类里面声明属性和方法。但是动态代理却不需要我们去新建java文件就能创建出一个类,在这个类里面就能实现我们想要的功能。

      在动态代理中有两个很重要的接口和类

          接口InvocationHandler,它是代理处理器类,被代理类的方法和增强效果就是在实现了这个接口的类中执行的,在InvocationHandler中有个方法

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable

          

这个方法的作用就是通过反射调用被代理对象的方法  ,  proxy就是创建动态代理实例的对象,method就是被代理类要执行的方法,args就是这个方法的参数。

         类Proxy,它的作用就是创建动态代理实例。我们主要调用Proxy的newProxyInstance方法来创建动态代理实例。

          

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

          参数loader就是被代理类的类加载器,加载代理对象;参数interfaces,就是被代理对象锁实现的接口,proxy创建的代理对象也要实现这个接口;参数h代理处理器类,将增强的方法传给proxy,让proxy创建出的动态代理对象里面有增强的效果。

       动态代理代码实现

 被代理接口          
/**
 * 照相机接口
 * @author user
 *
 */
public interface Camera {
	public void photo();

}
被代理类
/**
 * 索尼相机
 * @author user
 *
 */
public class CameraImp implements Camera{
    /**
     * 照相
     */
	public void photo() {
		System.out.println("给如花照了一张像");
		
	}
}

代理处理器
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 自动ps 其实就是给被代理对象的一些方法进行增强处理
 * @author user
 *
 */
public class AutoPs implements InvocationHandler{
    private Object camera =  null;
	public AutoPs(Object camera){
		this.camera = camera;
	}
	/**
	 * 当Camera的实例类在调用photo方法时,
	 * 实际上是将photo方法中功能是由invoke这个方法来完成的,
	 * 在完成的时候还带上了附加功能
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("自动给照片美白,使得每张照片都貌美如花"+method.getName());
		method.invoke(camera, args);
		return null;
	}
}

测试类
/**
 * 照相机代理,在照相的同时将美白功能加上
 * @author user
 *
 */
public class CameraProxyTest {
	
	public static void main(String[] args){
		//被代理对象
		CameraImp camera = new CameraImp();
		//代理对象处理器,动态代理对象调执行方法的时候,实际就是调用处理器的invoke方法
		AutoPs  ps = new AutoPs(camera);
		/*
		 * 生成动态代理对象cameraPs,创建的这个动态代理实例实现了被代理接口
		 * 被代理接口就是别代理对象实现了的接口,在这里就是Camera接口
		 */
		Camera cameraPs = (Camera)Proxy.newProxyInstance(camera.getClass().getClassLoader(), camera.getClass().getInterfaces(), ps);
		/*
		 * 动态代理对象由于实现了被代理接口
		 *  动态代理对象在执行方法的时候是由代理对象处理器的invoke方法在执行
		 *  invoke方法里面不仅执行了被代理对象的方法,而且还带上了一些额外功能。
		 */
		cameraPs.photo();
		
	}
}
输出结果
自动给照片美白,使得每张照片都貌美如花photo
给如花照了一张像
Camera cameraPs = (Camera)Proxy.newProxyInstance(camera.getClass().getClassLoader(), camera.getClass().getInterfaces(), ps);
这段代码就是创建出动态代理对象,这个对象继承了Proxy和实现了Carema接口。我们其实可以通过通过反编译工具查看cameraPs的代码的,这里我就模拟写出一个caremaPs的主要代码。
 
public class CameraPs  extends Proxy implements Camera{
	private static Method m; 
	protected CameraPs(InvocationHandler h) {
		super(h);
	}

	public void photo() {
		try {
			super.h.invoke(this, m, null);
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}
	
	 static    
	    {   
	        try  
	        {             
	            m = Class.forName("Camera").getMethod("photo", new Class[0]);   
	        }   
	        catch(NoSuchMethodException nosuchmethodexception)   
	        {   
	            throw new NoSuchMethodError(nosuchmethodexception.getMessage());   
	        }   
	        catch(ClassNotFoundException classnotfoundexception)   
	        {   
	            throw new NoClassDefFoundError(classnotfoundexception.getMessage());   
	        }   
	    }   
}
上面这段代码我调用里面的photo方法会出错,晕,这个类是为了更好地理解proxy创建的动态代理对象是什么样的啊

总结

几个比较重要的对象:

1.目标对象,被代理的对象。

2.目标对象实现的接口interface,目标对象和代理对象都会实现这个接口。

3.Proxy代理生成器,通关Proxy的newProxyInstance方法生成代理对象,在newProxyInstance方法中会传入目标对象的类加载器和接口,以及代理处理器,其中Proxy会利用目标接口和类加载器创建出代理对象,Proxy是真正拥有代理处理器的。

4.InvocationHandler代理处理器,代理处理器会实现InvocationHandler接口,重写invoke方法,在invoke方法中会利用反射调用目标对象的方法,其中代理处理器会对目标对象有引用。

5.代理对象,通过Proxy生成的代理对象,代理对象通过实现接口,继承Proxy,重写目标接口方法,通过Proxy获取到代理处理器,然后在重写的方法中调用代理处理器的invoke方法来进行处理。

jdk代理的流程:

1.创建被代理接口Camera和被代理对象CamearaImp;

2.创建代理处理器AutoPs,AutoPs实现了InvocationHandler接口,并实现了invoke方法,在这个方法中有附加效果和执行Carema的方法
3代理创建器Proxy的newProxyInstance方法创建动态的代理对象,newProxyInstance中要传入被代理类加载器,被代理接口和代理处理器。
创建的动态代理对象实现了被代理接口,实现接口的方法中调的是AutoPs的invoke方法。
上面所讲的就是我们在Spring AOP中所用的JDK代理,看起来屌屌的,但是有个缺点就是被代理对象必须要实现接口,cglib代理就不需要这么做。明天再看看cglib的实现原理是什么样的。看完动态代理就用一种迫不及待的想看Spring AOP源码了,这对理解Spring MVC中的HandlerAdapter这块应该有很大的帮助,以前看SpringMVC HandlerAdapter这一块不是特别清楚。
要想更深入理解动态代理请看:http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html
感觉离12K的薪资期望又近了一点,屌屌的。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值