【Spring】AOP底层实现原理
前言
AOP (Aspect Oriented Programing) ⾯向切⾯编程 = Spring动态代理开发
以切⾯为基本单位的程序开发,通过切⾯间的彼此协同,相互调⽤,完成程序的构建(切⾯ = 切⼊点(包、类、方法、注解) + 附加功能)
OOP (Object Oritened Programing) ⾯向对象编程 Java
以对象为基本单位的程序开发,通过对象间的彼此协同,相互调⽤,完成程序的构建
POP (Producer Oriented Programing) ⾯向过程(⽅法、函数)编程 C
以过程为基本单位的程序开发,通过过程间的彼此协同,相互调⽤,完成程序的构建
一、核心问题
1、AOP是什么(动态代理)
2、AOP如何创建动态代理类(动态字节码技术)
二、动态代理类的创建
代理创建的三要素:
1、原始对象
2、额外功能
3、代理对象和原始对象实现相同的接口(interface)
1.JDK的动态代理
Proxy.newProxyInstance⽅法参数详解
newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
//1、ClassLoader 借用的类加载器,用于创建代理类的Class对象,进而创建代理对象
//2、Class<?>[] interfaces userService.getClass().getInterfaces()
//3、InvocationHandler 用来写具体的附加功能,额外功能运行在原始方法执行前、后、前后、抛出异常
对于第三个参数需要手动实现
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
// 1、Proxy 可以忽略 代表的是代理对象
// 2、Method:需要加强的原始方法
// 3、args:原始方法的参数
Object o = method.invoke(userService, args);
//原始对象 原始对象参数
return o;
补充:ClassLoader 的作用
1、通过类加载器将类的字节码文件(.class)加载到JVM
2、通过类加载器创建类的Class对象,进而可以创建类的实例
如何获得类加载器:每个类的.class文件自动分配与之对应的ClassLoader(双亲委派)
思考:在动态代理的创建过程中,需要ClassLoader创建代理类的Class对象,可是动态代理类没有对应的.class文件,JVM也就不会为他分配ClassLoader,那怎么办?
答:借用一个
代码如下
public class TestJDKProxy {
/*
1. 借用类加载器 TestJDKProxy
UserServiceImpl
2. JDK8.x前
final UserService userService = new UserServiceImpl();
*/
public static void main(String[] args) {
//1 创建原始对象
UserService userService = new UserServiceImpl();
//2 JDK创建动态代理
UserServiceImpl proxyInstance = (UserServiceImpl) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new InvocationHandler() {
// ClassLoader 借用的类加载器,用于创建代理类的Class对象,进而创建代理对象
// Class<?>[] interfaces userService.getClass().getInterfaces()
// InvocationHandler 用来写具体的附加功能,额外功能运行在原始方法执行前、后、前后、抛出异常
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 参数:Proxy 可以忽略 代表的是代理对象
// Method:需要加强的原始方法
// args:原始方法的参数
Object o = method.invoke(userService, args);
return o;
}
});
proxyInstance.login("soso","123");
proxyInstance.register(new User());
}
}
2.CGlib的动态代理
对于有接口实现的类我们通过JDK创建动态代理对象,那么对于没有接口实现的类,我们怎么办?
CGlib创建动态代理的原理:⽗⼦继承关系创建代理对象,原始类作为⽗类,代理类作为⼦类,这样既可以保证2者⽅法⼀致,同时在代理类中提供新的实现(额外功能+原始⽅法)
CGlib编码
public class TestCglib {
public static void main(String[] args) {
//1 创建原始对象
UserService userService = new UserServiceImpl();
/*
2 通过cglib方式创建动态代理对象
Proxy.newProxyInstance(classloader,interface,invocationhandler)
Enhancer.setClassLoader()
Enhancer.setSuperClass()
Enhancer.setCallback(); ---> MethodInterceptor(cglib)
Enhancer.create() ---> 代理
*/
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(TestCglib.class.getClassLoader());
enhancer.setSuperclass(userService.getClass());
MethodInterceptor interceptor = new MethodInterceptor() {
//等同于 InvocationHandler --- invoke
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("---cglib log----");
Object ret = method.invoke(userService, args);
return ret;
}
};
enhancer.setCallback(interceptor);
UserService userServiceProxy = (UserService) enhancer.create();
userServiceProxy.login("suns", "123345");
userServiceProxy.register(new User());
}
}
总结
- JDK动态代理 Proxy.newProxyInstance() 通过接⼝创建代理的实现类
- Cglib动态代理 Enhancer 通过继承⽗类创建的代理类