前言
AOP面向切面编程,是基于OOP(面向对象编程)的补充和完善,spring中也提供了AOP的实现,这一系列博文将分析spring中AOP的实现步骤。
开启AOP
开启spring aop的功能,需要在xml文件中加入下面这行配置。
<aop:aspectj-autoproxy>
解析AOP自定义标签
在 Spring源码解读(二)Bean创建过程之解析——BeanDefinition 这篇博文中,解析配置文件时,会根据标签进行解析,当时只分析了<bean>标签的解析流程
DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 这里指处理spring命名空间的标签
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 解析默认的元素 "import", "alias", "bean".
parseDefaultElement(ele, delegate);
}
else {
// 解析自定义的标签 如 <tx:annotation-driven /> <aop:aspectj-autoproxy>
delegate.parseCustomElement(ele);
}
}
}
}
else {
// 解析自定义的标签 如 <tx:annotation-driven /> <aop:aspectj-autoproxy>
delegate.parseCustomElement(root);
}
}
解析自定义标签最主要的是定义命名空间和实现NameSpaceHandel命名空间处理器,spring会根据命名空间找到对应的处理器,委托对应的处理器解析自定义的标签。具体解析自定义标签的分析,会在写博文详细分析,这篇博文关注的是aop的标签解析。
AOP自定义标签处理器
aop定义了自己的标签处理器,如果识别到aspectj-autoproxt,将注册一个自动代理创建器 AnnotationAwareAspectJAutoProxyCreator
AopNamespaceHandler
public class AopNamespaceHandler extends NamespaceHandlerSupport {
/**
* Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
* '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
* and '{@code scoped-proxy}' tags.
*/
@Override
public void init() {
// In 2.0 XSD as well as in 2.5+ XSDs
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace in 2.5+
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
注册自动代理创建器 AnnotationAwareAspectJAutoProxyCreator
所有的解析器都必须实现BeanDefinitionParser接口,NamespaceHandlerSupport会调用BeanDefinitionParser定义的parser方法进行解析。
AspectJAutoProxyBeanDefinitionParser#parse
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 注册AnnotationAutoProxyCreatorIfNecessary
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
// 都注解中的子类处理
extendBeanDefinition(element, parserContext);
return null;
}
主要实现逻辑在AopNamespaceUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary中
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 注册AutoProxyCreator定义beanName为 org.springframework.aop.config.internalAutoProxyCreator的BeanDefinition
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 对 proxy-target-class 和 expose-proxy 属性处理
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 注册组件并通知,便于监听器做进一步处理
// beanDefinition的className为 AnnotationAwareAspectJAutoProxyCreator
registerComponentIfNecessary(beanDefinition, parserContext);
}
这个方法中主要做了三件事,每行代码就是一件事。
注册AspectJAnnotationAutoProxyCreator
aop的实现,几乎可以说是有AnnotationAwareAspectJAutoProxyCreator实现的 ,可以根据 @Point 注解定义的切点自动代理配备对应的Bean。
Spring采用自定义配置的实现自动注册AnnotationAwareAspectJAutoProxyCreator,这个方法就是它自动注册的过程。
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 如果已经存在了自动代理创建器且存在的自动创建器和现在的不一致,需要根据优先级判断使用哪一个
// AopConfigUtils的静态成员变量 AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator"
// 是否已经存在了自动代理创建器
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 存在的自动代理器和当前不一致
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
// 获取两个自动代理创建器的优先级参数
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
// 取优先级数字小的那一个创建器使用
// 指定className后,BeanDefinition就会使用这个class完成后续的操作
apcDefinition.setBeanClassName(cls.getName());
}
}
// 如果已经存在了创建器,且就是和当前这个一致,无需再次创建
return null;
}
// 创建这个自动代理创建器的BeanDefinition装饰类
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
// 实质优先级参数为最高优先级
// HIGHEST_PRECEDENCE = Integer.MIN_VALUE
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 注册bean并且指定beanName AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator"
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
对 proxy-target-class 和 expose-proxy 属性处理
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
if (sourceElement != null) {
// 标签中是否存在 proxy-target-class 属性
boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
// 对 proxy-target-class 进行处理
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
// 标签中是否存在 expose-proxy 属性
boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
// 对 expose-proxy 进行处理
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
处理 proxyTargetClass
为自动代理创建器设置 proxyTargetClass = true 表示使用代理目标类,spring aop 是基于代理实现的,代理有两种方式
- JDK动态代理:被代理对象至少实现一个接口,它是通过在运行期间创建一个接口实现类来完成对被代理对象的代理功能
- CGLIB代理:实现原理和JDK动态代理几乎一致,只是它在运行期间生成的代理对象是被代理对象类的扩展子类。他性能比JDK动态代理要强
默认情况下,如果被代理对象实现了至少一个接口,那么会使用JDK动态代理,否则则使用CGLIB代理。
若使用CGLIB代理会存在两个问题:
- 无法通知 final 修饰的方法,因为 final 修饰的方法不能被覆盖
- 需要将CJLIB二进制发行包放在classpath下面
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
处理exposeProxy
为自动代理创建器设置 exposeProxy = true 表示直接暴露代理, 被代理对象内部方法间自调用时,无法被 代理对象 代理,从而无法织入切点。
可通过设置 exposeProxy = true , 使用 AopContext.currentProxy() 获取到当前代理对象后再调用需要目标方法,这样就好比外部类调用当前代理的方法,可以被代理,从而实现织入切点,进行切面增强的效果。
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
必要时注册组件
注册组件并且通知,这里是留给以后监听器去处理的,暂不分析。
private static void registerComponentIfNecessary(@Nullable BeanDefinition beanDefinition, ParserContext parserContext) {
if (beanDefinition != null) {
parserContext.registerComponent(
new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));
}
}