IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> spring源码aop解析xml生成bean定义信息 -> 正文阅读

[Java知识库]spring源码aop解析xml生成bean定义信息

spring面向切面编程是咱们工作中使用比较频繁的一项技术,比如:日志、事务、表单重复提交等
了解aop之前需要先了解几个概念

  1. 什么是aspect :切面
  2. 什么是连接点:切面方法参数
  3. 切入点表达式:用于过滤目标方法的过滤器
  4. 什么是织入:通知方法的总称
  5. 什么是目标方法:被代理的对象方法

看下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;
}

以上是个人观点,有错误的地方还请指出,谢谢了

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-13 11:38:35  更:2022-05-13 11:40:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 21:28:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码