AOP就是Spring面向切面编程,经常会在调用某一个方法前或者调用以后去执行其他的操作,这就需要用到AOP原理了
AOP是怎么做到切面点切入的呢,就是通过动态代理来实现的,动态代理目前主要有JDK的动态代理(InvocationHandler)和Cglib两种
首先,最早接触到的代理应该是设计模式中的代理模式,是静态代理,主要是有接口类,接口实现类和代理类,代码如下
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019102110194620.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xoejEzNTEwOTcwNzQ1,size_16,color_FFFFFF,t_70)
代码如下:
接口类
package test;
public interface Caculate {
public int add(int a,int b);
public int sub(int a,int b);
}
接口实现类
package test;
public class AddCaculate implements Caculate{
@Override
public int add(int a, int b) {
// TODO Auto-generated method stub
return a+b;
}
@Override
public int sub(int a, int b) {
// TODO Auto-generated method stub
return a-b;
}
}
代理类
package test;
public class CaculateProxy implements Caculate{
private Caculate caculate;
public CaculateProxy(Caculate caculate) {
this.caculate=caculate;
// TODO Auto-generated constructor stub
}
@Override
public int add(int a, int b) {
// TODO Auto-generated method stub
return caculate.add(a, b);
}
@Override
public int sub(int a, int b) {
// TODO Auto-generated method stub
return caculate.add(a, b);
}
}
测试
AddCaculate addCaculate = new AddCaculate();
CaculateProxy proxy = new CaculateProxy(addCaculate);
proxy.add(1, 2);
proxy.sub(2, 1);
这里就是静态代理类的实现,那么问题来了,如果需要增添或者删除一些方法,那么代理类也要跟随着做相应的修改,此时就需要动态代理来解决这个问题了,那么动态代理是啥原理实现的呢,看下面一张图
这是java代码在jvm里边编译解析程子节码的过程,Java的源代码.java文件通过编译器编译成.class文件后,jvm就在加载类的时候,会根据.class的组织结构,生成对应的字节码 再进行加载类,这就实现了.class在运行期间才被确定,就成就了动态代理了
1.InvocationHandler模式
InvocationHandler就是在静态代理模式上引入了InvocationHandler类,这个类就是负责在运行时候,动态调用proxy所要调用的对应实现类的方法,代码如下
接口类和实现类还是和静态代理一样
代理类如下,实现了InvocationHandler:
package test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class CaculateProxy implements InvocationHandler{
private Object caculate;
public CaculateProxy(Object caculate) {
this.caculate=caculate;
// TODO Auto-generated constructor stub
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
method.invoke(caculate, args);
return null;
}
}
测试类
AddCaculate addCaculate = new AddCaculate();
InvocationHandler invocationHandler = new CaculateProxy(addCaculate);
Caculate caculate = (Caculate) Proxy.newProxyInstance(addCaculate.getClass().getClassLoader(),
addCaculate.getClass().getInterfaces(), invocationHandler);
caculate.add(2, 3);
caculate.sub(1, 2);
我们看到addCaculate.getClass(),这段代码实际上我们是把实现类中的接口信息与触发器invocationHandler绑定,也就是说如果实现类有接口中没有的方法是不能被代理的。总的来说,JDK这种代理1)要保证有接口,2)不能代理接口中没有的方法
为避免上面的两种缺陷,这就是要说的另一种动态代理实现方式,那就是代理类继承被代理类,不需要接口,这种实现如 Cglib,Cglib是实现了MethodInterceptor拦截器
它的流程是这样的:
1).查找A上的所有非final 的public类型的方法定义;
2).将这些方法的定义转换成字节码;
3).将组成的字节码转换成相应的代理的class对象;
4).实现 MethodInterceptor接口,用来处理 对代理类上所有方法的请求(这个接口和JDK动态代理InvocationHandler的功能和角色是一样的
本文参考文章:http://blog.csdn.net/luanlouis/article/details/24589193