什么是AOP
AOP (Aspect Orient Programming),直译过来就是 面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。
为什么需要AOP
想象下面的场景,开发中在多个模块间有某段重复的代码,我们通常是怎么处理的?显然,没有人会靠“复制粘贴”吧。在传统的面向过程编程中,我们也会将这段代码,抽象成一个方法,然后在需要的地方分别调用这个方法,这样当这段代码需要修改时,我们只需要改变这个方法就可以了。然而需求总是变化的,有一天,新增了一个需求,需要再多出做修改,我们需要再抽象出一个方法,然后再在需要的地方分别调用这个方法,又或者我们不需要这个方法了,我们还是得删除掉每一处调用该方法的地方。实际上涉及到多个地方具有相同的修改的问题我们都可以通过 AOP 来解决。
AOP的实现
AOP本质上其实是代理模式,定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理。
jdk动态代理实现
基本类
//定义的接口HelloService
public interface HelloService {
void sayHello();
}
//接口的实现类
public class HelloServiceImpl implements HelloService {
public void sayHello() {
System.out.println("Hello");
}
}
通知类
//Advice,继承了 InvocationHandler 接口
public interface Advice extends InvocationHandler {
}
//实现了 Advice 接口,是一个前置通知
public class BeforeAdvice implements Advice{
//真实类的对象
private Object bean;
//通知内容
private MethodInvocation methodInvocation;
public BeforeAdvice(Object bean,MethodInvocation methodInvocation){
this.bean=bean;
this.methodInvocation=methodInvocation;
}
//当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置通知内容
methodInvocation.invoke();
// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(bean, args);
return null;
}
}
//通知内容,实现类包含了切面逻辑
public interface MethodInvocation {
void invoke();
}
AOP实现类
//生成代理类
public class SimpleAOP {
public static Object getProxy(Object bean,Advice advice){
return Proxy.newProxyInstance(SimpleAOP.class.getClassLoader(),bean.getClass().getInterfaces(), advice);
}
}
测试类
public class TestAop {
public static void main(String[] args) {
// 1. 创建一个 MethodInvocation 实现类
MethodInvocation logTask = () -> System.out.println("log task start");
HelloServiceImpl helloServiceImpl = new HelloServiceImpl();
// 2. 创建一个 Advice
Advice beforeAdvice = new BeforeAdvice(helloServiceImpl,logTask);
// 3. 为目标对象生成代理
HelloService helloServiceImplProxy = (HelloService) SimpleAOP.getProxy(helloServiceImpl,beforeAdvice);
//调用方法
helloServiceImplProxy.sayHello();
}
}
附加
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy: - 指代我们所代理的那个真实对象
method: - 指代的是我们所要调用真实对象的某个方法的Method对象
args: - 指代的是调用真实对象某个方法时接受的参数
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上