您的位置:首页 > 编程语言 > Java开发

Spring源码阅读-注解实现AOP

2017-07-21 00:00 627 查看
写配置文件对很多人来说是一件比较痛苦的事,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的子类。

3ff0

再看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 <aop:include> 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是怎么使用这些代理创建器创建代理对象的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring aop