前言
如果很多对象需要aop, 按前面一篇每个对象单独配置实现方式太麻烦,spring提供了通用的配置方式,不需要单独指定代理对象。
看个例子:
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;
}
}
public class PersonAdvice {
public void before() throws Throwable {
System.out.println("before......");
}
public void after() throws Throwable {
System.out.println("after......");
}
}
<bean id="person" class="com.myframe.modules.test.service.impl.Person">
<property name="name" value="zhangsan"></property>
</bean>
<!-- 准备切点跟advice -->
<bean id="beforeAfterAdvice" class="com.myframe.modules.test.service.impl.PersonAdvice">
</bean>
<aop:config>
<aop:aspect id="aspect" ref="beforeAfterAdvice">
<aop:pointcut id="queryPoincut" expression="execution(* com.myframe.modules.test.service.impl.**.query*(..))" />
<aop:before method="before" pointcut-ref="queryPoincut"/>
<aop:after method="after" pointcut-ref="queryPoincut"/>
</aop:aspect>
</aop:config>
这里通过配置一个queryPoincut来匹配满足expression规则对象来实现切面,调用person的query开头的方法会先调用beforeAfterAdvice的before方法,最后调用after方法,如下:
before......
name:zhangsan
after......
这里具体expression是怎么匹配的,以及怎么创建代理的先不看,先看这个配置是怎么被spring加载的。
加载配置
下面又是长篇大论的贴代码。。。。。
首先根据标签找到对应的handler, 在AopNamespaceHandler里面定义了标签对应的处理类:
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());
}
}
这里我们看config的ConfigBeanDefinitionParser的parse方法:
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(),
parserContext.extractSource(element));
//把创建的复合componet放入栈中
parserContext.pushContainingComponent(compositeDef);
// 注册,嵌入到复合component
configureAutoProxyCreator(parserContext, element);
// 解析子元素
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt : childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
parsePointcut(elt, parserContext);
} else if (ADVISOR.equals(localName)) {
parseAdvisor(elt, parserContext);
} else if (ASPECT.equals(localName)) {
//解析aspect标签
parseAspect(elt, parserContext);
}
}
//注册整个复合component
parserContext.popAndRegisterContainingComponent();
return null;
}
ParserContext中有个栈用于存放复合组件,pushContainingComponent和popAndRegisterContainingComponent是spring对复合组件注册的通用用法,这两步操作中间部分是我们比较关心的内容,
1. configureAutoProxyCreator
跟踪configureAutoProxyCreator方法调用:
private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}
public static void registerAspectJAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {
//把 AspectJAwareAdvisorAutoProxyCreator初始化成BeanDefinition
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
//对proxyTargetClass和exposeProxy判断, 并把值设置到上面的beanDefinition属性中
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
//把beanDefinition创建成BeanComponentDefinition并注册到复合组件中的内部集合
registerComponentIfNecessary(beanDefinition, parserContext);
}
这里主要三步:创建、设置属性、注册。
1)创建
AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary把自动代理创建器初始化成BeanDefinition,内部会有一些判断逻辑:
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry,
Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
//如果已经存在并且名字不相同就比较一下优先级
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
//如果当前优先级低则改变class
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
//注册BeanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
默认使用的代理创建器是AspectJAwareAdvisorAutoProxyCreator,如果已经注册了对应的自动代理创建器并且名字不相同,则比较一下优先级,最终目的就是生成BeanDefinition。
(这里怎么会已经存在自动代理创建器AUTO_PROXY_CREATOR_BEAN_NAME的?这个可以在spring的配置文件中指定,也可以在spring的beanFactory启动后用自定义扩展点手动设置进去,spring的对象工厂就是这么灵活,处处可以设置对象,可以设置任何对象。)
2)设置属性
接着上面useClassProxyingIfNecessary方法,BeanDefinition创建完成后还要对其设置一些属性,这里设置了两个属性:proxyTargetClass和exposeProxy,后面具体用到的时候再看。
3)注册
registerComponentIfNecessary方法是把beanDefinition创建成BeanComponentDefinition,然后注册到前面栈中复合组件的内部集合中。
2. 解析子标签
aop:config下面可以有三子标签(aop:aspect, aop:pointcut, aop:advisor),功能都差不多,只是解析的对象不同而已,这里只以aspect一个流程看其思想。
根据上面的例子来跟踪代码,定位到parseAspect(elt, parserContext)方法:
private void parseAspect(Element aspectElement, ParserContext parserContext) {
String aspectId = aspectElement.getAttribute(ID);
String aspectName = aspectElement.getAttribute(REF);
try {
this.parseState.push(new AspectEntry(aspectId, aspectName));
List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
List<BeanReference> beanReferences = new ArrayList<BeanReference>();
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
Element declareParentsElement = declareParents.get(i);
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
}
// We have to parse "advice" and all the advice kinds in one loop,
// to get the
// ordering semantics right.
NodeList nodeList = aspectElement.getChildNodes();
boolean adviceFoundAlready = false;
//===============================================
//循环先对advice型节点进行处理
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (isAdviceNode(node, parserContext)) {
if (!adviceFoundAlready) {
adviceFoundAlready = true;
if (!StringUtils.hasText(aspectName)) {
parserContext.getReaderContext().error(
"<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
aspectElement, this.parseState.snapshot());
return;
}
//第一次会获取依赖的aspect对象名称
beanReferences.add(new RuntimeBeanReference(aspectName));
}
//创建advisor的BeanDefinition
AbstractBeanDefinition advisorDefinition = parseAdvice(aspectName, i, aspectElement, (Element) node,
parserContext, beanDefinitions, beanReferences);
beanDefinitions.add(advisorDefinition);
}
}
//把上面的aspect生成的beanDefinitions一起生成组件,然后压入栈中
AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(aspectElement,
aspectId, beanDefinitions, beanReferences, parserContext);
parserContext.pushContainingComponent(aspectComponentDefinition);
//最后操作pointcut节点
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
parsePointcut(pointcutElement, parserContext);
}
parserContext.popAndRegisterContainingComponent();
} finally {
this.parseState.pop();
}
}
//判断是不是advice节点
private boolean isAdviceNode(Node aNode, ParserContext parserContext) {
if (!(aNode instanceof Element)) {
return false;
} else {
String name = parserContext.getDelegate().getLocalName(aNode);
return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name)
|| AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));
}
}
1) advisor
上面代码循环部分对aspect下面的advice标签进行处理,这里的advice标签只包含before, after, after-returning, after-throwing, around,看一下他们是怎么处理,重点跟进parseAdvice方法:
private AbstractBeanDefinition parseAdvice(String aspectName, int order, Element aspectElement,
Element adviceElement, ParserContext parserContext, List<BeanDefinition> beanDefinitions,
List<BeanReference> beanReferences) {
try {
this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
// create the method factory bean
RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
methodDefinition.setSynthetic(true);
// create instance factory definition
RootBeanDefinition aspectFactoryDef = new RootBeanDefinition(
SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);
// register the pointcut
AbstractBeanDefinition adviceDef = createAdviceDefinition(adviceElement, parserContext, aspectName, order,
methodDefinition, aspectFactoryDef, beanDefinitions, beanReferences);
// configure the advisor
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(adviceElement));
advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
}
// register the final advisor
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
return advisorDefinition;
} finally {
this.parseState.pop();
}
}
这里主要是把before after这些方法转成BeanDefinition后创建一个名为adviceDef的BeanDefinition,看创建方法createAdviceDefinition的实现:
private AbstractBeanDefinition createAdviceDefinition(Element adviceElement, ParserContext parserContext,
String aspectName, int order, RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
//根据标签获取class
RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
adviceDefinition.setSource(parserContext.extractSource(adviceElement));
//设置属性
adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
if (adviceElement.hasAttribute(RETURNING)) {
adviceDefinition.getPropertyValues().add(RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
}
if (adviceElement.hasAttribute(THROWING)) {
adviceDefinition.getPropertyValues().add(THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
}
if (adviceElement.hasAttribute(ARG_NAMES)) {
adviceDefinition.getPropertyValues().add(ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
}
//构造参数,主要包括三块:METHOD_INDEX、POINTCUT_INDEX、ASPECT_INSTANCE_FACTORY_INDEX
ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
Object pointcut = parsePointcutProperty(adviceElement, parserContext);
if (pointcut instanceof BeanDefinition) {
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
beanDefinitions.add((BeanDefinition) pointcut);
} else if (pointcut instanceof String) {
RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
beanReferences.add(pointcutRef);
}
cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
return adviceDefinition;
}
private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
String elementName = parserContext.getDelegate().getLocalName(adviceElement);
if (BEFORE.equals(elementName)) {
return AspectJMethodBeforeAdvice.class;
} else if (AFTER.equals(elementName)) {
return AspectJAfterAdvice.class;
} else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
return AspectJAfterReturningAdvice.class;
} else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
return AspectJAfterThrowingAdvice.class;
} else if (AROUND.equals(elementName)) {
return AspectJAroundAdvice.class;
} else {
throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
}
}
adviceDef的class根据具体标签来定:
BEFORE | AspectJMethodBeforeAdvice |
AFTER | AspectJAfterAdvice |
AFTER_RETURNING_ELEMENT | AspectJAfterReturningAdvice |
AFTER_THROWING_ELEMENT | AspectJAfterThrowingAdvice |
AROUND | AspectJAroundAdvice |
其他的就是设置一些属性,其中比较重要的就是ConstructorArgumentValues。
接着上面的parseAdvice方法:创建完adviceDef后再把它作为构造参数创建advisorDefinition,advisorDefinition的class为AspectJPointcutAdvisor,这样一个切面包含的advice和pointcut就在一个advisorDefinition中了, 最后注册到BeanFactory中。
advisorDefinition创建完毕后会一起把他们构造成AspectComponentDefinition复合组件,然后压入栈中,在看一下上面的parseAspect方法:
private void parseAspect(Element aspectElement, ParserContext parserContext) {
String aspectId = aspectElement.getAttribute(ID);
String aspectName = aspectElement.getAttribute(REF);
try {
//...
//把上面的aspect生成的beanDefinitions一起生成组件,然后压入栈中
AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(aspectElement,
aspectId, beanDefinitions, beanReferences, parserContext);
parserContext.pushContainingComponent(aspectComponentDefinition);
//最后操作pointcut节点
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
parsePointcut(pointcutElement, parserContext);
}
parserContext.popAndRegisterContainingComponent();
} finally {
this.parseState.pop();
}
}
2) pointcut
parseAspect最后解析的标签是pointcut,看一下parsePointcut方法的代码:
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
String id = pointcutElement.getAttribute(ID);
String expression = pointcutElement.getAttribute(EXPRESSION);
AbstractBeanDefinition pointcutDefinition = null;
try {
this.parseState.push(new PointcutEntry(id));
//创建expression对应的BeanDefinition
pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
String pointcutBeanName = id;
if (StringUtils.hasText(pointcutBeanName)) {
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
} else {
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}
//注册到aspect复合组件内部集合
parserContext.registerComponent(
new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
} finally {
this.parseState.pop();
}
return pointcutDefinition;
}
protected AbstractBeanDefinition createPointcutDefinition(String expression) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
beanDefinition.setSynthetic(true);
beanDefinition.getPropertyValues().add(EXPRESSION, expression);
return beanDefinition;
}
创建expression的BeanDefinition并注册到beanFactory中,最后注册到aspect复合组件的内部集合中,这里expression的class是AspectJExpressionPointcut。
总结
这篇讲了用配置文件方式配置aop,spring是如何解析加载的,还没有讲到具体如何使用加载的这些BeanDefinition,这个里面一个核心类AspectJAwareAdvisorAutoProxyCreator就是创建动态代理的核心类,他的子类AnnotationAwareAspectJAutoProxyCreator是用注解方式是注册的,它们的上层抽象类AbstractAutoProxyCreator实现了创建代理的核心逻辑。
后面一篇会看一下用@Aspect注解时spring是如何加载的,再下一篇会看AbstractAutoProxyCreator是怎么创建动态代理的。