文档章节

Spring源码阅读-注解实现AOP

Small-Liu
 Small-Liu
发布于 2017/07/21 17:36
字数 779
阅读 41
收藏 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
粉丝 16
博文 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
spring-AOP原理与应用

什么是AOP Spring是解决实际开发中的一些问题: * AOP解决OOP中遇到的一些问题.是OOP的延续和扩展. AOP作用 对程序进行增强:不修改源码的情况下. * AOP可以进行权限校验,日志记录,性能监控,事...

叫我北北
06/29
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

没有更多内容

加载失败,请刷新页面

加载更多

中秋快乐!!!

HiBlock
35分钟前
1
0
Node安装教程

1、安装最新版的node 2、设置相关目录(以D盘为例) 分别建立目录:D:\node,D:\node\node-globa,D:\node\node-cache 命令行输入: // 设置npm国内镜像 npm config set registry https://re...

Mohan710
今天
3
0
中国发布域名系统基础软件 “红枫”

9月12日消息,域名工程中心(英文缩写 ZDNS)发布了宣称自主开发的域名系统基础软件 “红枫(Maple DNS)”。 9月12日消息,域名工程中心(英文缩写 ZDNS)发布了宣称自主开发的域名系统基础软...

问题终结者
今天
3
0
Shell编程(分发系统介绍、expect远程登录、expect远程执行命令、expect传递参数)

分发系统介绍expect 分发系统expect即分发脚本,是一种脚本语言;通过他可以实现传输,输入命令(上线代码) 应用场景:业务越来越大,网站app,后端,编程语言是php,所以就需要配置lamp或者...

蛋黄_Yolks
今天
4
0
Java Http请求工具类

public static String httpPost(String source, String params) {URL url = null;HttpURLConnection conn = null;OutputStream os = null;String ret = null;try {......

yuewawa
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部