Insight Spring3 @RequestMapping 自定义Aspect不生效问题

问题背景

现有项目使用Spring3 框架,想要对应用所有的请求进行统一监控。

一种方案是配置全局的 HandlerInterceptor,实现对请求的监控。

一种方案是基于AOP,拦截@RequestMapping,实现对Controller 的方法进行监控。项目中采用的是这种方案,主要目的是收集方法粒度的性能、可用率的数据。

问题描述

编写完自定义的Aspect 监控类后,发现切面不生效。

在spring-config.xml 中配置启用了@AspectJ 特性。

<!--Enables the use of the @AspectJ style of Spring AOP.-->
<aop:aspectj-autoproxy proxy-target-class="true" />

使用的是Spring3 的框架,web.xml 中集成Spring 配置如下所示

<!-- spring3 常见的配置方式,分为Spring容器配置 和 SpringMVC 配置,两个配置文件中各自扫描对应的包路径 -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>classpath:spring-config.xml</param-value>
</context-param>
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
	<servlet-name>springmvc</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-config-mvc.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

源码分析

首先确认自定义的AOP Bean 是正常加载后,剩下的问题就是探究为什么<aop:aspectj-autoproxy/>没有生效。

aspectj-autoproxy 配置分析

aspectj-autoproxy 配置的工作原理参考 Insight aop:aspectj-autoproxy 解析

通过该配置,会给Spring 容器注册AnnotationAwareAspectJAutoProxyCreator, 属于BeanPostProcessor 组件,这样的话,就会在生成bean 的以后,根据Bean的特征,对bean 生成代理类。

作用:checking for marker interfaces or wrapping them with proxies.

对应到本案例,就是检查是否存在 @RequestMapping 注解,并对符合条件的bean 进行代理,实现监控功能的增强。

通过检查AspectJ 语法和对应的路径,发现也正常,那么问题就可能出现在Spring 容器中。

spring mvc 配置分析

通过上述的web.xml 配置,可以分析出存在两个spring 容器,容器是父子的关系。

// listener配置的父容器
// Bootstrap listener to start up and shut down Spring's root WebApplicationContext
// org.springframework.web.context.ContextLoader#initWebApplicationContext
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

// servlet 配置的子容器
// Instantiate the WebApplicationContext for this servlet
ConfigurableWebApplicationContext wac = BeanUtils.instantiateClass(XmlWebApplicationContext.class);
wac.setEnvironment(getEnvironment());
// set root WebApplicationContext
wac.setParent(parent);

按照正常的思路来看,子容器应该能集成父容器的特性和注册的解析器、处理器等。

事实证明,父容器注册AnnotationAwareAspectJAutoProxyCreator,子容器不会查找和使用。这也是AOP代理不生效的原因

对比getBean的获取机制

/**
 * 根据指定的类型,返回唯一的bean
 * 如果在当前的BeanFactory 找不到,会委托给父BeanFactory 查找,从而实现递归查找的策略
 */
public <T> T getBean(Class<T> requiredType) throws BeansException {
	Assert.notNull(requiredType, "Required type must not be null");
	String[] beanNames = getBeanNamesForType(requiredType);
	if (beanNames.length > 1) {
		// ......
	}
	if (beanNames.length == 1) {
		return getBean(beanNames[0], requiredType);
	}
	else if (beanNames.length == 0 && getParentBeanFactory() != null) {
        // 从父容器中查找指定的Bean
		return getParentBeanFactory().getBean(requiredType);
	}
	else {
		throw new NoSuchBeanDefinitionException(requiredType, "expected single bean but found " +
				beanNames.length + ": " + StringUtils.arrayToCommaDelimitedString(beanNames));
	}
}


解决方法和总结

需要在子容器的配置文件中添加:<aop:aspectj-autoproxy proxy-target-class="true" />

或者合并容器的配置,统一由servlet 启动加载。

从父容器中获取Bean 的方法:

org.springframework.beans.factory.BeanFactoryUtils#beansOfTypeIncludingAncestors()

备注

AOP - Aspect Oriented Programming

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Source Insight 3是一款功能强大的面向项目的编程编辑器,代码浏览器和分析器。它可以帮助程序员在工作和计划时更好地理解代码。很多嵌入式工程师选择使用Source Insight来查看和编辑Linux内核代码,因为它可以处理大量的代码。\[1\] 另外,如果你需要Source Insight 3的序列号,以下是一些序列号供你参考:SI3US-205035-36448、SI3US-466908-65897、SI3US-368932-59383、SI3US-065458-30661、SI3US-759512-70207。\[2\] 如果你对Java、Android、C/C++等技术感兴趣,可以关注公众号\[懒人漫说\],他们会分享相关技术知识,并解答你在学习过程中遇到的问题。他们也是正在成长的程序员,会分享自己的成长经历和感想,希望能和你一起努力成长。\[3\] #### 引用[.reference_title] - *1* [Source Insight3 看代码神器](https://blog.csdn.net/qq_37474534/article/details/80435822)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Source Insight 3.x serial 序列号](https://blog.csdn.net/u013005025/article/details/52525813)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值