什么是AOP?
简单理解:方法增强。
AOP是一种编程范式,与语言无关,是一种程序设计思想。
面向切面编程(AOP)Aspect Oriented Programming。
切面编程的目的是为了把通用逻辑从业务逻辑分离出来。
AOP可以增强方法的功能,而不需要修改原业务代码。
深入理解
从编程语言的角度:处理粒度不同
AOP是对OOP的扩展,OOP(即面向对象编程)能处理的最大粒度是对象,对OOP而言,当需要增强方法的功能时,必须修改类的定义。而AOP能处理的粒度可以深入到对象内部,可以是方法或者字段(Spring暂不支持字段增强),所以AOP可以使我们不用重新定义类,而增强原方法。
从设计模式的角度:AOP进一步降低了模块间的耦合度
使得业务代码和功能性代码分离,降低它们之间的耦合度。
功能性代码,如:事务处理、参数校验、日志、监控、负载均衡
从解放程序员生产力的角度:更少的代码
AOP只需要少量的配置或者注解就可以完成
从代码可读性的角度:业务逻辑更清晰
程序员可以更聚焦于业务逻辑。
AOP的核心是什么?
动态代理
AOP主要是做什么?(动态代理做什么?)
对那些被代理对象的那些方法在方法运行到那些时段做什么增强。
JDK动态代理
JDK动态代理不需要重写实现类,也不需要定义一个实现UserService接口的代理类。而是使用Proxy类帮我们动态生成代理类。
package day05.Agent2;
import day05.Agent.UserService;
import java.lang.reflect.Proxy;
import java.text.SimpleDateFormat;
import java.util.Date;
//jdk
public class UserServiceProxy {
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* 返回动态代理对象
* @param userService 被代理对象
* @return 代理对象
*/
public static UserService newProxyInstance(UserService userService) {
/*
* Proxy.newProxyInstance方法返回动态生成的代理类
* 参数:
* userService.getClass().getClassLoader():被代理类的类加载器;
* userService.getClass().getInterfaces():被代理类的接口,重要!说明JDK动态代理是基于代理接口的。
* 第三个参数定义了一个内部类,实现了代理逻辑,内部参数:
* o:代理类对象;
* method:被代理方法;
* objects:被代理方法的参数;
*/
return (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(), (o, method, objects) -> {
// 调用被代理方法
Object ret = method.invoke(userService, objects);
// 编写增强功能
System.out.println(dateFormat.format(new Date()) + ": method " + method.getName() + " invoked");
return ret;
});
}
}
test:
package day05;
import day05.Agent.UserService;
import day05.Agent.UserServiceImpl;
import day05.Agent2.Impl;
public class client {
public static void main(String[] args) {
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
UserService userService = Impl.newInstance(new UserServiceImpl());
userService.getUser();
userService.createUser();
userService.updateUser();
userService.deleteUser();
}
}
Cglib动态代理
public class UserServiceCglibProxy {
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* 返回动态代理对象
* @param userService 被代理对象
* @return 代理对象
*/
public static UserService newProxyInstance(UserService userService) {
/*
* Enhancer.create方法返回动态生成的代理类
* 参数:
* userService.getClass():被代理类的类;
* 第二个参数定义了一个内部类,实现了代理逻辑,内部参数:
* o:代理类对象;
* method:被代理方法;
* objects:被代理方法的参数;
* methodProxy:方法代理;
*/
return (UserService) Enhancer.create(userService.getClass(), (MethodInterceptor) (o, method, objects, methodProxy) -> {
// 调用被代理方法
Object ret = methodProxy.invokeSuper(o, objects);
// 编写增强功能
System.out.println(dateFormat.format(new Date()) + ": method " + method.getName() + " invoked");
return ret;
});
}
}
test:
public static void main(String[] args) {
// 保存动态生成的代理类的字节码
// System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\code");
UserService userService = UserServiceCglibProxy.newProxyInstance(new UserServiceImpl());
userService.getUser();
userService.createUser();
userService.updateUser();
userService.deleteUser();
}
二者区别
简单理解
使用场景
JDK动态代理用于接口
例如,我们要代理UserServiceImpl,则UserServiceImpl必须实现一个接口,例如UserService接口;
Cglib用于类或者接口
例如,我们要代理UserServiceImpl,不需要关注该类是否实现接口。
效率
Java8之前,Cglib效率高;
Java8开始,JDK动态代理效率高;
深入理解
为什么JDK动态代理必须要有接口,而Cglib则不需要
这是由他们的实现方式决定的。
JDK动态代理生成类继承关系