Spring源码阅读-注解实现AOP

原创
2017/07/21 17:36
阅读数 729

写配置文件对很多人来说是一件比较痛苦的事,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是怎么使用这些代理创建器创建代理对象的。

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部