最近在找工作,许多面试官都比较喜欢问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;