AOP编程
1.AOP概念
AOP(Aspect Oriented Programing)
:面向切面编程,以切面为基本单位的程序开发,通过切面见得彼此协同、相互调用、完成程序的构建。
- 面向切面编程 = Spring的动态代理开发
- 切面 = 切入点+ 额外功能
OOP(Object Oriented Programing)
:面向对象编程,以对象为基本单位的程序开发,通过对象见得彼此协同,相互调用,完成程序的构建。
POP(Producer Oriented Programing)
:面向过程(方法、函数)编程,以过程为及本单位的程序开发,通过过程间的的彼此协同,相互调用,完成程序的构建。
总之:
- AOP的本质:就是Spring的动态代理,通过代理类为原始类增加额外功能。
- 好处:有利于原始类的维护
- 注意:AOP编程不可能取代OOP,AOP编程时OOP的补充,因为面向切面编程的前提也是要有对象。
2. AOP的开发步骤
因为AOP编程就是Spring的动态代理,所以AOP编程的开发步骤与Spring动态代理开发步骤一样:
- 原始对象
- 额外功能(
MethodInterceptor
) - 切入点
- 组装切面(额外功能+切入点)
4. AOP的底层实现原理
1. 核心问题
1.AOP如何创建动态代理类?
答:动态字节码结束
2. Spring工厂如何进行加工创建代理对象?
答:通过原始对象的id值,获得的是代理对象
2. 动态代理类的创建
创建代理对象的三要素:
- 原始对象
- 额外功能
- 原始对象与代理对象实现相同的接口
2.1JDK的动态代理
-
Proxy.newProxyInstance
方法参数详解
newProxyInstance
方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
ClassLoader
:动态代理类没有对应的.class
文件,JVM也就不会为其分配ClassLoader,所以需要借用一个ClassLoader,用来创建代理类的Class
对象,进而可以创建代理对象。
interfaces
:原始对象所实现的接口(代理三要素第3点)
InvocationHandler
:用于书写额外功能(代理三要素第2点)
InvocationHandler invocationHandler = new InvocationHandler() {
/**
* @param proxy 代理对象(可以忽略掉)
* @param method 额外功能所增加给的那个原始方法
* @param args 原始方法的参数
* @return 原始方法的返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
};
-
类加载器
-
类加载器作用:
1. 通过类加载器把对应类的字节码文件加载到JVM中 2. 通过类加载器创建类的Class对象,进而创建这个类的对象
-
如何获得类加载器
每一个类的.class文件自动分配与之对应的ClassLoader
对于动态代理而言,没有静态代理那样手写一个代理类,所以动态代理类也就没有.class文件,JVM就不会为其分配类加载器。虽然通过动态字节码技术可以创建字节码直接写入到JVM中,但是必须通过类加载器才能创建类的Class对象,所以需要借一个ClassLoader,才能创建这个类的对象。
-
-
JDK动态代理编码
public class TestJDKProxy { public static void main(String[] args) { //1. 原始对象 UserService userService = new UserServiceImpl(); //2. jdk创建动态代理 InvocationHandler invocationHandler = new InvocationHandler() { /** * @param proxy 代理对象(可以忽略掉) * @param method 额外功能所增加给的那个原始方法 * @param args 原始方法的参数 * @return 原始方法的返回值 * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("---jdk log---"); Object ret = method.invoke(userService, args); System.out.println("---jdk log---"); return ret; } }; //获取代理对象 UserService userServiceProxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), invocationHandler); userService.login("zhangsan", "法外狂徒"); userService.register(new User()); userServiceProxy.login("zhangsan", "法外狂徒"); userServiceProxy.register(new User()); } }
2.2 CGlib的动态代理
CGlib创建动态代理的原理:父子继承关系创建代理对象,原始类作为父类,代理类作为子类,这样既可以保证二者方法一致,同时在代理类中提供新的实现(额外功能+原始方法)
有时候原始类没有实现任何接口,要想代理类与原始类拥有相同的接口 ,就可以通过继承实现。
-
CGlib与jdk
动态代理区别 -
CGlib
编码public class TestCGlib { public static void main(String[] args) { //1. 创建原始对象 UserService userService = new UserService(); //2. CGlib动态代理 Enhancer enhancer = new Enhancer(); enhancer.setClassLoader(TestCGlib.class.getClassLoader()); //没有与原始类实现相同接口,而是采用继承实现,所以与jdk动态代理不一样,不是设置原始类所有接口,而是设置原始类类型 enhancer.setSuperclass(userService.getClass()); MethodInterceptor interceptor = new MethodInterceptor() { @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); System.out.println("---cglib log---"); return ret; } }; enhancer.setCallback(interceptor); UserService userServiceProxy = (UserService) enhancer.create(); userServiceProxy.login("zhangsan", "zhangsan"); userServiceProxy.register(new User()); } }