spring中AOP实现分析-第一篇

前言

这是一篇关于Spring AOP的总结分析文章,帮助自己记忆。

AOP配置

下面的例子是通过注解驱动的AOP例子:

启用Spring AOP:

1
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>

或者通过下面的注解方式启用Spring AOP

1
2
3
4
5
6
7
8
/**
* @author jiexiu
*/
@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
@Configuration
public class Config {

}

待增强的类:

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @author jiexiu
* created 2020/5/29 - 22:48
*/
@Service
public class HelloService implements IHelloService {

@Override
public String sayHello(String msg) {
return "hi : " + msg;
}
}

配置切面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* @author jiexiu
*/
@Aspect
@Component
public class AopAspect {
/**
* 可重用的切点
*/
@Pointcut("execution(* com.leokongwq.springlearn.service.IHelloService.*(..))")
public void perform() {
}

@Before("perform()")
public void beforeInvoke() {
System.out.println("########### before invoke ###############");
}
}

通过上面的步骤我们就配置好了一个简单的Spring AOP 使用例子。

执行效果如下:

1
########### around before invoke ###############

为了简单起见,不在演示切点表达式如何写,这种Advice的效果。

效果有了,那spring究竟是如何实现的呢?分析如下。

Spring 实现 AOP分析

1
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>

这配置究竟有何魔法呢?答案就在于对aop命名空间的处理上。如下所示:

AopNamespaceHandler

1
2
3
4
5
6
7
8
9
10
11
public class AopNamespaceHandler extends NamespaceHandlerSupport {
public AopNamespaceHandler() {
}

public void init() {
this.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
this.registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}

通过代码可以知道aspectj-autoproxy起作用的原因在于,该配置向Spring容器中注册了相关Bean。
我们关系的是AspectJAutoProxyBeanDefinitionParser

AspectJAutoProxyBeanDefinitionParser

1
2
3
4
5
public BeanDefinition parse(Element element, ParserContext parserContext) {
//这一步很重要,代理类的Creator就是在这一步注册到Spring容器中的 AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
this.extendBeanDefinition(element, parserContext);
return null;
}

AopNamespaceUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
```

### AopConfigUtils

```java
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}

return null;
} else {
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", -2147483648);
beanDefinition.setRole(2);
registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
return beanDefinition;
}
}

到这步AnnotationAwareAspectJAutoProxyCreator.class就被注册到容器中了。

AnnotationAwareAspectJAutoProxyCreator

1
2
3
4
5
6
7
8
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
}

public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
}

public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
}

AbstractAutoProxyCreator

1
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

重头戏来了:AbstractAutoProxyCreator实现了接口:SmartInstantiationAwareBeanPostProcessor。 该接口是Spring提供给开发者的一个扩展点,

SmartInstantiationAwareBeanPostProcessor
1
2
3
4
5
6
7
8
9
10
11
12

// 预测Bean的类型,返回第一个预测成功的Class类型,如果不能预测返回null
Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException;

// 选择合适的构造器,比如目标对象有多个构造器,在这里可以进行一些定制化,选择合适的构造器
// beanClass参数表示目标实例的类型,beanName是目标实例在Spring容器中的name
// 返回值是个构造器数组,如果返回null,会执行下一个PostProcessor的determineCandidateConstructors方法;否则选取该PostProcessor选择的构造器
Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException;

// 获得提前暴露的bean引用。主要用于解决循环引用的问题
// 只有单例对象才会调用此方法
Object getEarlyBeanReference(Object bean, String beanName) throws BeansException;

AbstractAutoProxyCreator 就是使用了接口的扩展能力,对创建的Bean进行代理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
//如果需要就对目前对象进行AOP代理
return this.wrapIfNecessary(bean, beanName, cacheKey);
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
} else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
} else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//创建代理类
Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
} else {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
} else {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}

创建代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);
}

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
//如果么有设置 proxy-target-class 配置项为true, 并且被增强Bean也没有实现接口
//那么spring还是会通过CGLIB进行代理
//如果设置proxy-target-class为true,那么就算目标实现接口,也会进行CGLIB增强
if (!proxyFactory.isProxyTargetClass()) {
if (this.shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
this.evaluateProxyInterfaces(beanClass, proxyFactory);
}
}

Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
this.customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (this.advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//创建代理类
return proxyFactory.getProxy(this.getProxyClassLoader());
}

DefaultAopProxyFactory

该类负责具体代理的创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
public DefaultAopProxyFactory() {
}

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// JDK 动态代理
if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
return new JdkDynamicAopProxy(config);
} else {
//CGLIB 代理
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));
}
}
}

private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return ifcs.length == 0 || ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]);
}
}

JdkDynamicAopProxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

@Override
truepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
true // 如果配置了exposeProxy,那么Spring就会将代理对象放入ThreadLocal中
true // 如果是CGLIB, 可以查看类:DynamicUnadvisedExposedInterceptor
if (this.advised.exposeProxy) {
truetruetruetrue// Make invocation available if necessary.
truetruetruetrueoldProxy = AopContext.setCurrentProxy(proxy);
truetruetruetruesetProxyContext = true;
truetrue}
true}
true
true@Override
truepublic Object getProxy(ClassLoader classLoader) {
truetrueif (logger.isDebugEnabled()) {
truetruetruelogger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
truetrue}
truetrueClass<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
truetruefindDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
truetrue// 这行代码应该非常熟悉了
truetruereturn Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
true}
}

JdkDynamicAopProxy 作用有2个(CglibAopProxy同理):

  1. 创建代理对象。
  2. 拦截目标对象的方法调用,实现增强。这个从类的签名就可以知道,它实现了接口InvocationHandler,并且在创建JDK代理对象时,将this作为参数传入Proxy.newProxyInstance方法。

总结

  1. spring 既可以基于接口也可以基于类对目标对象进行AOP增强。
  2. proxy-target-class默认为false,在默认配置下,Spring会自动判是基于接口还是类进行AOP增强。
  3. 如果将proxy-target-class设置为true,那么统一执行基于的类的通过CGLIB实行的AOP增强。
  4. expose-proxy 默认为false,当设置为true时,即暴露出代理对象。内部使用的是ThreadLocal来实现代理对象的暴露。可以通过AopContext.currentProxy()获取代理对象(在Spring事务方法中获取代理对象,调用另一个事务方法,形成嵌套事务)。
文章目录
  1. 1. 前言
  2. 2. AOP配置
  3. 3. Spring 实现 AOP分析
    1. 3.1. AopNamespaceHandler
    2. 3.2. AspectJAutoProxyBeanDefinitionParser
    3. 3.3. AopNamespaceUtils
    4. 3.4. AnnotationAwareAspectJAutoProxyCreator
    5. 3.5. AbstractAutoProxyCreator
    6. 3.6. 创建代理类
    7. 3.7. DefaultAopProxyFactory
    8. 3.8. JdkDynamicAopProxy
  4. 4. 总结
|