AOP原理
通过前两节的学习,我们了解并熟悉了如何使用 AOP,作为热爱编程的程序员,应主动了解底层原理,知道它是如何实现的。
AOP代理原理讲解
我们知道 xml 中,AOP 使用的是 ProxyFactoryBean,而且底层原理相同,因此我们从这里讲起。首先,看这个类,如下所示。
public class ProxyFactoryBean extends ProxyCreatorSupport implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware
图5.4是这个类的继承关系图。

从图中可以看到 ProxyFactoryBean 类继承了 ProxyCreatorSupport 类。ProxyCreatorSupport 类比较重要,下面有创建工厂与获取代理工厂。我们来看 ProxyCreatorSupport 下的方法,如图5.5所示。

在图中有两个方法,一个为 createAopProxy,另一个为 getAopProxyFactory。我们先来看看 getAopProxyFactory方法,如下所示。
private AopProxyFactory aopProxyFactory;
public ProxyCreatorSupport() {
this.aopProxyFactory = new DefaultAopProxyFactory();
}
从程序中可以发现,AopProxyFactory 由 DefaultAopProxyFactory 来实现。这里有个方法是 createAopProxy,用来判断我们的代理是 JDK 还是 cglib,代码如下所示。
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException
{
if(!config.isOptimize()&&!config.isProxyTargetClass()&& !this.hasNoUserSuppliedProxyInterfaces(config)) {
return new JdkDynamicAopProxy(config);
} else {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
} else {
return (AopProxy)(!targetClass.isInterface() && !Proxy. isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
}
}
}
在上面的代码中,首先判断是否有接口,如果有接口,则直接 new JdkDynamicAopProxy。如果没有接口,就从 AdvisedSupport 中获取目标对象 Class,然后对这个对象进行判断。在这里 JDK 的代理是 JdkDynamicAopProxy,cglib 的代理是 ObjenesisCglibAopProxy。
那么如何获取代理?DefaultAopProxyFactory 中可以产生两种 AopProxy 接口,这时内部逻辑可以根据给定的类创建不同的代理 AopProxy,因为这时返回的是 AopProxy 接口。
那么这个接口是怎样的?代码如下所示。
package org.springframework.aop.framework;
import org.springframework.lang.Nullable;
public interface AopProxy {
Object getProxy();
Object getProxy(@Nullable ClassLoader var1);
}
ProxyCreatorSupport核心代理类
上文介绍 ProxyFactoryBean 类时主要讲了其内部的两个方法,将方向指到了 AOP 的代理上,下面就讲它的子类。通过 IDEA 可以看到其类的子类,如图5.6所示。

ProxyFactory
ProxyFactory 类也是用于创建 proxy 对象的工厂类,一般用于动态应用 AOP 时,编程式地使用 AOP 代理。在使用时,需要为它指定需要代理的目标对象,代理时需要 Advice、Advisor。我们通过一个使用 ProxyFactory 创建代理的实例,进行介绍说明,代码如下所示。
public void testProxyFactory() {
MyService myService = new MyService();
ProxyFactory proxyFactory = new ProxyFactory(myService);
proxyFactory.addAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行目标方法调用之前的逻辑");
}
});
MyService proxy = (MyService) proxyFactory.getProxy();
proxy.add();
}
先看看 ProxyFactory 的方法,如图5.7所示。

在上面的代码中,使用的是构造函数指定代理的对象,也可以使用父类 AdvisedSupport 中的 setTarget 方法设置代理。
在上面程序中的关于 MethodBeforeAdvice 的使用方法,会在5.3.3小节中进行说明。
AspectJProxyFactory
AspectJProxyFactory 类主要是用于集成 AspectJ 与 Spring。在上面的代码中,可以看到 ProxyFactory 能够绑定 Advice 与 Advisor,非常方便。但当在代码中已有存在的切面,这时使用 ProxyFactory 就不够方便。不过 Spring Boot 提供了 AspectJProxyFactory 类,可以直接指定代理对象的切面。
这个类一般用于基于 AspectJ 风格的 AOP 代理对象。举例说明,首先我们需要一个存在的切面,代码如下所示。
package com.springBoot.aop.aspect;
@Aspect
@Component
public class LogAscpect {
private Logger logger=LoggerFactory.getLogger(LogAscpect. class);
@Pointcut("execution( * com.springBoot.aop.pojo.impl.MyLogPrint.doPrint(..))")
public void pointCut(){
}
@Before("pointCut()")
public void before(){
System.out.println("before log");
}
}
下面是使用 AspectJProxyFactory 类的代码。
public void aspectJProxyFactoryDemo() {
MyService myService = new MyService();
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(myService);
proxyFactory.addAspect(LogAscpect.class);
proxyFactory.setProxyTargetClass(true);
MyService proxy = proxyFactory.getProxy();
proxy.add();
}
在上面的代码中可以看到,proxyFactory.addAspect 将已经存在的切面与代理绑定。
通知和通知器
在5.2节讲解了连接点,也讲解了切面与切点,这里认识一下通知和通知器。
通知(Advice)
首先,我们需要知道通知(Advice)在连接点做什么。其实通知只是一个标识接口,没有具体的方法与定义,代码如下所示。
package org.aopalliance.aop;
public interface Advice {
}
但是常用的通知都需要继承 Advice。例如,我们看 AfterReturningAdvice 接口,用于连接点执行完返回执行的通知,代码如下所示。
package org.springframework.aop;
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(@Nullable Object var1, Method var2, Object[] var3, @Nullable Object var4) throws Throwable;
}
上面的代码中,我们可以看到参数是返回值 var1、目标方法 var2、参数 var3、目标方法类 var4。在连接点执行之后,会在这个方法中执行切面逻辑。
通知器(Advisor)
我们了解了切点(Pointcut)、通知(Advice),只要将切点与通知结合就可以变成通知器(Advisor)。我们来看通知器的接口,代码如下所示。
package org.springframework.aop;
import org.aopalliance.aop.Advice;
public interface Advisor {
Advice EMPTY_ADVICE = new Advice() {
};
Advice getAdvice();
boolean isPerInstance();
}
再看子接口的代码。
package org.springframework.aop;
public interface PointcutAdvisor extends Advisor {
Pointcut getPointcut();
}
这里包含了两个重要的方法:getPointcut 与 getAdvice。