spring面向切面编程是咱们工作中使用比较频繁的一项技术,比如:日志、事务、表单重复提交等
了解aop之前需要先了解几个概念
- 什么是aspect :切面
- 什么是连接点:切面方法参数
- 切入点表达式:用于过滤目标方法的过滤器
- 什么是织入:通知方法的总称
- 什么是目标方法:被代理的对象方法
看下AOP处理器 ConfigBeanDefinitionParser
总结下:
Advice有五个类别:AspectJMethodBeforeAdvice、AspectJAfterAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice、AspectJAroundAdvice;这5个类别都需要三个构造方法,(Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif),并且需要pointcut的支持去拦截目标对象方法;所有的通知最后会被包装成Advisor
public class AopNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
xml配置
<bean id="bookServiceImpl" class="com.msgqu.debug.aop.service.BookServiceImpl"></bean>
<!-- 配置切面的bean -->
<bean id="logAspect" class="com.msgqu.debug.aop.log.LogAspect"></bean>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut id="pointcut" expression="execution(* com.msgqu.debug.aop.service.*.*(..))"/>
<!-- 配置切面及通知 -->
<aop:aspect ref="logAspect">
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
解析自定义标签
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 获取到命名空间url,aop的在spring-aop服务下的 META-INF文件夹下的spring.handlers文件中配置
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 根据namespaceUri找到对应的处理器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// 使用对应命名空间解析器执行解析
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
获取对应的解析器,并进行解析
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionParser parser = findParserForElement(element, parserContext);
return (parser != null ? parser.parse(element, parserContext) : null);
}
获取bean定义信息的解析器
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
// 获取标签名称 如:aop:config解析成config
String localName = parserContext.getDelegate().getLocalName(element);
// 根据标签名称获取对应解析器
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
ConfigBeanDefinitionParser.parse 根据标签解析bean定义信息
// parserContext包含三个重点信息:1、xml上下文读取器2、bean定义信息的解析委托器3、一个栈
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 创建一个复合的组件定义信息
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
// 把当前标签的定义信息放入栈中
parserContext.pushContainingComponent(compositeDef);
// 现在parserContext中包含了解析后bean定义信息
// 配置自动代理创建器
configureAutoProxyCreator(parserContext, element);
// 获取到aop:config下的子标签
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
configureAutoProxyCreator 配置自动代理创建器
private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
//如果需要注册Aspectj自动代理创建器
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}
// xml和注解底层处理逻辑基本是一致的
// @Import(AspectJAutoProxyRegistrar.class)
// public @interface EnableAspectJAutoProxy {
// 咱们springboot 使用的这个注解@EnableAspectJAutoProxy底层也是调用的这个方法
public static void registerAspectJAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {
// 这里主要是注册了一个AspectJAwareAdvisorAutoProxyCreator的bean定义信息
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 设置配置的属性,未配置,默认为false,不进行设置 proxy-target-class、expose-proxy
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 注册到复合组件中 (CompositeComponentDefinition aop:config中)
registerComponentIfNecessary(beanDefinition, parserContext);
}
// 向工厂中注册一个org.springframework.aop.config.internalAutoProxyCreator的bean定义信息
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
//实际干活的方法
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//如果bean定义信息Map中存在org.springframework.aop.config.internalAutoProxyCreator
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 如果class信息不一致,重新设置下优先级
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
// 已经存在bean定义信息了,无需走下面的流程了
return null;
}
// 创建一个bean定义信息
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
// 设置最高的优先级
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
// 设置bean定义信息的角色为内部使用的bean
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 注册到工厂中
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
parsePointcut 解析pointcut
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
// 获取标签id
String id = pointcutElement.getAttribute(ID);
// 获取标签表达式
String expression = pointcutElement.getAttribute(EXPRESSION);
AbstractBeanDefinition pointcutDefinition = null;
try {
// 把pointcut的id放到队列
this.parseState.push(new PointcutEntry(id));
// 创建pointcut定义信息 class=AspectJExpressionPointcut.class
// 这里比较有意思的是原型模式
pointcutDefinition = createPointcutDefinition(expression); pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
// 注册pointcut bean定义信息
String pointcutBeanName = id;
if (StringUtils.hasText(pointcutBeanName)) {
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
}else {
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}
// 前面咱们已经注册了一个AutoProxyCreate,现在又注册了一个pointcut
parserContext.registerComponent(new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
}finally {
this.parseState.pop();
}
return pointcutDefinition;
}
parseAspect 解析aspect标签
所有的通知advice统称为advisor(顾问)
private void parseAspect(Element aspectElement, ParserContext parserContext) {
String aspectId = aspectElement.getAttribute(ID);
// 获取到切面引用id
String aspectName = aspectElement.getAttribute(REF);
try {
// 标识解析到哪个标签
this.parseState.push(new AspectEntry(aspectId, aspectName));
List<BeanDefinition> beanDefinitions = new ArrayList<>();
List<BeanReference> beanReferences = new ArrayList<>();
// 这里可以忽略,一般不会配置
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
Element declareParentsElement = declareParents.get(i);
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
}
// 获取到aspect的子标签通知
NodeList nodeList = aspectElement.getChildNodes();
boolean adviceFoundAlready = false;
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
// 验证是这些标签才会解析(before、after、after-returning、after-throwing、around)
if (isAdviceNode(node, parserContext)) {
if (!adviceFoundAlready) {
adviceFoundAlready = true;
if (!StringUtils.hasText(aspectName)) {
parserContext.getReaderContext().error("<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",aspectElement, this.parseState.snapshot());
return;
}
beanReferences.add(new RuntimeBeanReference(aspectName));
}
// 创建advisor定义信息
AbstractBeanDefinition advisorDefinition = parseAdvice(aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
// 添加到容器
beanDefinitions.add(advisorDefinition);
}
}
// 创建aspect组件定义信息
AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
// 注册到aop:config定义信息的嵌套组件集合中
parserContext.pushContainingComponent(aspectComponentDefinition);
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
parsePointcut(pointcutElement, parserContext);
}
// 注册到
parserContext.popAndRegisterContainingComponent();
}
finally {
this.parseState.pop();
}
}
parseAdvice 解析通知生成bean定义信息
private AbstractBeanDefinition parseAdvice(
String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
try {
// 记录解析栈
this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
// create the method factory bean
// 创建MethodLocatingFactoryBean的定义信息
RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
methodDefinition.setSynthetic(true);
// create instance factory definition
// 准备AOP的实例工厂,工厂是一个BeanFactoryAware
RootBeanDefinition aspectFactoryDef = new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);
// register the pointcut
// advice对应的class AspectJMethodBeforeAdvice、AspectJAfterAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice、AspectJAroundAdvice
AbstractBeanDefinition adviceDef = createAdviceDefinition(adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,beanDefinitions, beanReferences);
// configure the advisor
// 创建顾问定义信息
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(adviceElement));
advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
}
// register the final advisor
// 通知的定义信息并没有进行注册,只注册了advisor到容器中
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
return advisorDefinition;
}
finally {
this.parseState.pop();
}
}
createAdviceDefinition 创建通知的定义信息
private AbstractBeanDefinition createAdviceDefinition(
Element adviceElement, ParserContext parserContext, String aspectName, int order,
RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
// 创建advice定义信息
// 这里class可能为AspectJMethodBeforeAdvice、AspectJAfterAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice、AspectJAroundAdvice
RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
adviceDefinition.setSource(parserContext.extractSource(adviceElement));
//设置切面的名称
adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
// 设置优先级
adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
// 设置returning
if (adviceElement.hasAttribute(RETURNING)) {
adviceDefinition.getPropertyValues().add(RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
}
// 设置throwing
if (adviceElement.hasAttribute(THROWING)) {
adviceDefinition.getPropertyValues().add(THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
}
// 设置参数名称
if (adviceElement.hasAttribute(ARG_NAMES)) {
adviceDefinition.getPropertyValues().add(ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
}
// 获取构造方法参数,并按照参数下标赋值
// 构造方法在AbstractAspectJAdvice中有定义
// Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory
// aspectJAdviceMethod当前的通知方法,pointcut是切入点表达式,aspectInstanceFactory实例工厂
ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
// 设置当前通知
cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
// 设置切入点表达式
Object pointcut = parsePointcutProperty(adviceElement, parserContext);
if (pointcut instanceof BeanDefinition) {
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
beanDefinitions.add((BeanDefinition) pointcut);
}
else if (pointcut instanceof String) {
RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
beanReferences.add(pointcutRef);
}
// 设置实例工厂
cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
// 返回定义信息
return adviceDefinition;
}
以上是个人观点,有错误的地方还请指出,谢谢了