文档章节

Spring源码阅读-注解实现AOP

Small-Liu
 Small-Liu
发布于 2017/07/21 17:36
字数 779
阅读 54
收藏 0

写配置文件对很多人来说是一件比较痛苦的事,spring为了使用更方便也支持了用注解实现AOP,看个例子:

@Aspect
public class AspectJTest {

	@Pointcut(value="execution(* com.myframe.modules.test.service.impl.**.query*(..))")
	public void pointcut() {
		
	}
	@Before(value="pointcut()")
	public void before() {
		System.out.println("before==========");
	}
	@After(value="pointcut()")
	public void after() {
		System.err.println("after===========");
	}
}

public class Person implements IPerson {
	private String name;
	public String queryName() {
		System.out.println("name:" + name);
		return name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}
<bean id="person" class="com.myframe.modules.test.service.impl.Person">
	<property name="name" value="zhangsan"></property>
</bean> 

<bean class="com.myframe.modules.test.service.impl.AspectJTest"></bean>

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

执行结果:

before==========
name:zhangsan
after===========

上面配置需要注意的是AspectJTest 对象也要被加载到BeanFactory中才会生效,spring并不会扫描@Aspect注解来创建对象,只会根据该注解创建切面。

 

虽说用注解可以实现aop,但是注解本身还是需要配置来驱动的,找到aop:aspectj-autoproxy对应的处理类:

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.1 XSD.
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

		// Only in 2.0 XSD: moved to context namespace as of 2.1
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}
}

跟踪AspectJAutoProxyBeanDefinitionParser的parse方法:

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
		extendBeanDefinition(element, parserContext);
		return null;
	}
}
public abstract class AopNamespaceUtils {
	//默认自动代理创建器
	public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext,
			Element sourceElement) {

		BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
				parserContext.getRegistry(), parserContext.extractSource(sourceElement));
		useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
		registerComponentIfNecessary(beanDefinition, parserContext);
	}
}
public abstract class AopConfigUtils {
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
			Object source) {
		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}
}

看到这里的逻辑跟前一篇configureAutoProxyCreator 注册自动代理创建器逻辑一样,只是默认类变成了AnnotationAwareAspectJAutoProxyCreator,它是AspectJAwareAdvisorAutoProxyCreator的子类。

 

再看extendBeanDefinition(element, parserContext); 这个方法是用来处理aop:aspectj-autoproxy的子标签aop:include的,目的是把include的name属性取出来设置到代理创建器的 includePatterns 属性中,看代码:

private void extendBeanDefinition(Element element, ParserContext parserContext) {
	BeanDefinition beanDef = parserContext.getRegistry()
			.getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
	if (element.hasChildNodes()) {
		addIncludePatterns(element, parserContext, beanDef);
	}
}

private void addIncludePatterns(Element element, ParserContext parserContext, BeanDefinition beanDef) {
	ManagedList<TypedStringValue> includePatterns = new ManagedList<TypedStringValue>();
	NodeList childNodes = element.getChildNodes();
	for (int i = 0; i < childNodes.getLength(); i++) {
		Node node = childNodes.item(i);
		// 就一个子标签include, 只要判断是不是元素
		if (node instanceof Element) {
			Element includeElement = (Element) node;
			TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute("name"));
			valueHolder.setSource(parserContext.extractSource(includeElement));
			includePatterns.add(valueHolder);
		}
	}
	if (!includePatterns.isEmpty()) {
		includePatterns.setSource(parserContext.extractSource(element));
		//把include中的name取出来设置到代理创建器的includePatterns属性中
		beanDef.getPropertyValues().add("includePatterns", includePatterns);
	}
}

这个includePatterns是用来过滤aspect的,如果没有配置则所有被@Aspect修饰的对象都生效,如果配置了,则aspect对象名称必须至少满足一个include name的规则(正则表达式),这些从includePatterns使用的地方就可以知道,如下:

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
	/**
	 * Check whether the given aspect bean is eligible for auto-proxying.
	 * <p>
	 * If no &lt;aop:include&gt; elements were used then "includePatterns" will
	 * be {@code null} and all beans are included. If "includePatterns" is
	 * non-null, then one of the patterns must match.
	 */
	protected boolean isEligibleAspectBean(String beanName) {
		if (this.includePatterns == null) {
			return true;
		} else {
			for (Pattern pattern : this.includePatterns) {
				//正则表达式
				if (pattern.matcher(beanName).matches()) {
					return true;
				}
			}
			return false;
		}
	}
}

 

跟前一篇比较用注解实现aop只是入口不一样,最终目的还是把代理创建器以BeanDefinition的形式注册到BeanFactory中,后一篇会看spring是怎么使用这些代理创建器创建代理对象的。

© 著作权归作者所有

共有 人打赏支持
Small-Liu
粉丝 17
博文 56
码字总数 49976
作品 0
南京
程序员
私信 提问
Spring AOP 源码分析 - 筛选合适的通知器

1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析。本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出合适的通知器(Advisor...

java高级架构牛人
06/21
0
0
那些年,我们一起追的Spring

学无止境,但仍需及时总结。 自去年开始写作以来,写了一些关于Spring的文章,今天将它们汇总起来,一方面方便大家阅读,另一方面,也是一次小的复盘总结。 IOC 首先是Spring的IOC,也就是控...

SexyCode
08/14
0
0
Spring AOP 的实现方式(以日志管理为例)

Spring AOP 的实现方式(以日志管理为例) 2016年10月08日 00:13:57 阅读数:23198 在学习Spring框架的历程中,最重要的是要理解Spring的IOC和AOP了,不但要学会怎么用,最好是知道它是怎么实...

Jeam_
07/04
0
0
IOC/AOP工具 - jBeanBox

jBeanBox是一个微形但功能较齐全的IOC/AOP工具适用于JAVA7+,利用了Java的初始化块实现的Java配置代替XML。jBeanBox采用Apache License 2.0开源协议。 其他一些IOC/AOP框架的问题: 1)Sprin...

yong9981
2016/07/25
0
14
qiujiayu/AutoLoadCache

AutoLoadCache 现在使用的缓存技术很多,比如Redis、 Memcache 、 EhCache等,甚至还有使用ConcurrentHashMap 或 HashTable 来实现缓存。但在缓存的使用上,每个人都有自己的实现方式,大部分...

qiujiayu
09/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

技术工坊|如何开发一款以太坊钱包(深圳)

【好消息!】HiBlock区块链技术工坊已经成功举办了26期,其中北京1期,西安1期,成都2期,上海22期。经常有社区的小伙伴问定期举办技术工坊的除了上海以外,其他城市有没有?现在区块链技术工...

HiBlock
14分钟前
1
0
Redis 梳理笔记

安装 安装gccyum install gcc-c++下载传输到服务器上解压tar -xzvf *.tar.gzcd redis-3.2.9编译make安装 make PREFIX=/usr/local/redis install将配置文件拷贝出来cp redis...

晨猫
16分钟前
0
0
PyCharm flask 'Debug mode off' 调试模式关闭的解决方法

flask的几种debug模式的方法 # 1.app.run 传参debug=trueapp.run(debug=True) #2 设置app的配置app = Flask(__name__)app.config['DEBUG'] = True #3 配置文件方式# config.py中添加d...

yimingkeji
23分钟前
1
0
聊聊storm TridentWindowManager的pendingTriggers

序 本文主要研究一下storm TridentWindowManager的pendingTriggers TridentBoltExecutor.finishBatch storm-core-1.2.2-sources.jar!/org/apache/storm/trident/topology/TridentBoltExecut......

go4it
29分钟前
1
0
java实现多线程两种基本方式

我们在开发当中经常会使用到多线程,这里我们来写两个小案例通过最基本的两种方式继承Thread类或实现Runnable接口来实现一个多线程。 继承Thread类 我们可以通过继承Thread类,并重写run()方...

王子城
30分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部