1 /* 2 * Copyright 2002-2008 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.springframework.aop.config; 18 19 import java.util.ArrayList; 20 import java.util.List; 21 22 import org.w3c.dom.Element; 23 import org.w3c.dom.Node; 24 import org.w3c.dom.NodeList; 25 26 import org.springframework.aop.aspectj.AspectJAfterAdvice; 27 import org.springframework.aop.aspectj.AspectJAfterReturningAdvice; 28 import org.springframework.aop.aspectj.AspectJAfterThrowingAdvice; 29 import org.springframework.aop.aspectj.AspectJAroundAdvice; 30 import org.springframework.aop.aspectj.AspectJExpressionPointcut; 31 import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice; 32 import org.springframework.aop.aspectj.AspectJPointcutAdvisor; 33 import org.springframework.aop.aspectj.DeclareParentsAdvisor; 34 import org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor; 35 import org.springframework.beans.factory.config.BeanDefinition; 36 import org.springframework.beans.factory.config.BeanReference; 37 import org.springframework.beans.factory.config.ConstructorArgumentValues; 38 import org.springframework.beans.factory.config.RuntimeBeanNameReference; 39 import org.springframework.beans.factory.config.RuntimeBeanReference; 40 import org.springframework.beans.factory.parsing.CompositeComponentDefinition; 41 import org.springframework.beans.factory.parsing.ParseState; 42 import org.springframework.beans.factory.support.AbstractBeanDefinition; 43 import org.springframework.beans.factory.support.BeanDefinitionBuilder; 44 import org.springframework.beans.factory.support.BeanDefinitionRegistry; 45 import org.springframework.beans.factory.support.RootBeanDefinition; 46 import org.springframework.beans.factory.xml.BeanDefinitionParser; 47 import org.springframework.beans.factory.xml.ParserContext; 48 import org.springframework.util.StringUtils; 49 import org.springframework.util.xml.DomUtils; 50 51 /** 52 * {@link BeanDefinitionParser} for the <code><aop:config></code> tag. 53 * 54 * @author Rob Harrop 55 * @author Juergen Hoeller 56 * @author Adrian Colyer 57 * @author Mark Fisher 58 * @author Ramnivas Laddad 59 * @since 2.0 60 */ 61 class ConfigBeanDefinitionParser implements BeanDefinitionParser { 62 63 private static final String ASPECT = "aspect"; 64 private static final String EXPRESSION = "expression"; 65 private static final String ID = "id"; 66 private static final String POINTCUT = "pointcut"; 67 private static final String ADVICE_BEAN_NAME = "adviceBeanName"; 68 private static final String ADVISOR = "advisor"; 69 private static final String ADVICE_REF = "advice-ref"; 70 private static final String POINTCUT_REF = "pointcut-ref"; 71 private static final String REF = "ref"; 72 private static final String BEFORE = "before"; 73 private static final String DECLARE_PARENTS = "declare-parents"; 74 private static final String TYPE_PATTERN = "types-matching"; 75 private static final String DEFAULT_IMPL = "default-impl"; 76 private static final String DELEGATE_REF = "delegate-ref"; 77 private static final String IMPLEMENT_INTERFACE = "implement-interface"; 78 private static final String AFTER = "after"; 79 private static final String AFTER_RETURNING_ELEMENT = "after-returning"; 80 private static final String AFTER_THROWING_ELEMENT = "after-throwing"; 81 private static final String AROUND = "around"; 82 private static final String RETURNING = "returning"; 83 private static final String RETURNING_PROPERTY = "returningName"; 84 private static final String THROWING = "throwing"; 85 private static final String THROWING_PROPERTY = "throwingName"; 86 private static final String ARG_NAMES = "arg-names"; 87 private static final String ARG_NAMES_PROPERTY = "argumentNames"; 88 private static final String ASPECT_NAME_PROPERTY = "aspectName"; 89 private static final String DECLARATION_ORDER_PROPERTY = "declarationOrder"; 90 private static final String ORDER_PROPERTY = "order"; 91 private static final int METHOD_INDEX = 0; 92 private static final int POINTCUT_INDEX = 1; 93 private static final int ASPECT_INSTANCE_FACTORY_INDEX = 2; 94 95 private ParseState parseState = new ParseState(); 96 97 parse(Element element, ParserContext parserContext)98 public BeanDefinition parse(Element element, ParserContext parserContext) { 99 CompositeComponentDefinition compositeDef = 100 new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); 101 parserContext.pushContainingComponent(compositeDef); 102 103 configureAutoProxyCreator(parserContext, element); 104 105 List<Element> childElts = DomUtils.getChildElements(element); 106 for (Element elt: childElts) { 107 String localName = parserContext.getDelegate().getLocalName(elt); 108 if (POINTCUT.equals(localName)) { 109 parsePointcut(elt, parserContext); 110 } 111 else if (ADVISOR.equals(localName)) { 112 parseAdvisor(elt, parserContext); 113 } 114 else if (ASPECT.equals(localName)) { 115 parseAspect(elt, parserContext); 116 } 117 } 118 119 parserContext.popAndRegisterContainingComponent(); 120 return null; 121 } 122 123 /** 124 * Configures the auto proxy creator needed to support the {@link BeanDefinition BeanDefinitions} 125 * created by the '<code><aop:config/></code>' tag. Will force class proxying if the 126 * '<code>proxy-target-class</code>' attribute is set to '<code>true</code>'. 127 * @see AopNamespaceUtils 128 */ configureAutoProxyCreator(ParserContext parserContext, Element element)129 private void configureAutoProxyCreator(ParserContext parserContext, Element element) { 130 AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element); 131 } 132 133 /** 134 * Parses the supplied <code><advisor></code> element and registers the resulting 135 * {@link org.springframework.aop.Advisor} and any resulting {@link org.springframework.aop.Pointcut} 136 * with the supplied {@link BeanDefinitionRegistry}. 137 */ parseAdvisor(Element advisorElement, ParserContext parserContext)138 private void parseAdvisor(Element advisorElement, ParserContext parserContext) { 139 AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext); 140 String id = advisorElement.getAttribute(ID); 141 142 try { 143 this.parseState.push(new AdvisorEntry(id)); 144 String advisorBeanName = id; 145 if (StringUtils.hasText(advisorBeanName)) { 146 parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef); 147 } 148 else { 149 advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef); 150 } 151 152 Object pointcut = parsePointcutProperty(advisorElement, parserContext); 153 if (pointcut instanceof BeanDefinition) { 154 advisorDef.getPropertyValues().add(POINTCUT, pointcut); 155 parserContext.registerComponent( 156 new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut)); 157 } 158 else if (pointcut instanceof String) { 159 advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut)); 160 parserContext.registerComponent( 161 new AdvisorComponentDefinition(advisorBeanName, advisorDef)); 162 } 163 } 164 finally { 165 this.parseState.pop(); 166 } 167 } 168 169 /** 170 * Create a {@link RootBeanDefinition} for the advisor described in the supplied. Does <strong>not</strong> 171 * parse any associated '<code>pointcut</code>' or '<code>pointcut-ref</code>' attributes. 172 */ createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext)173 private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) { 174 RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class); 175 advisorDefinition.setSource(parserContext.extractSource(advisorElement)); 176 177 String adviceRef = advisorElement.getAttribute(ADVICE_REF); 178 if (!StringUtils.hasText(adviceRef)) { 179 parserContext.getReaderContext().error( 180 "'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot()); 181 } 182 else { 183 advisorDefinition.getPropertyValues().add( 184 ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef)); 185 } 186 187 if (advisorElement.hasAttribute(ORDER_PROPERTY)) { 188 advisorDefinition.getPropertyValues().add( 189 ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY)); 190 } 191 192 return advisorDefinition; 193 } 194 parseAspect(Element aspectElement, ParserContext parserContext)195 private void parseAspect(Element aspectElement, ParserContext parserContext) { 196 String aspectId = aspectElement.getAttribute(ID); 197 String aspectName = aspectElement.getAttribute(REF); 198 199 try { 200 this.parseState.push(new AspectEntry(aspectId, aspectName)); 201 List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>(); 202 List<BeanReference> beanReferences = new ArrayList<BeanReference>(); 203 204 List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS); 205 for (int i = METHOD_INDEX; i < declareParents.size(); i++) { 206 Element declareParentsElement = declareParents.get(i); 207 beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext)); 208 } 209 210 // We have to parse "advice" and all the advice kinds in one loop, to get the 211 // ordering semantics right. 212 NodeList nodeList = aspectElement.getChildNodes(); 213 boolean adviceFoundAlready = false; 214 for (int i = 0; i < nodeList.getLength(); i++) { 215 Node node = nodeList.item(i); 216 if (isAdviceNode(node, parserContext)) { 217 if (!adviceFoundAlready) { 218 adviceFoundAlready = true; 219 if (!StringUtils.hasText(aspectName)) { 220 parserContext.getReaderContext().error( 221 "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.", 222 aspectElement, this.parseState.snapshot()); 223 return; 224 } 225 beanReferences.add(new RuntimeBeanReference(aspectName)); 226 } 227 AbstractBeanDefinition advisorDefinition = parseAdvice( 228 aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences); 229 beanDefinitions.add(advisorDefinition); 230 } 231 } 232 233 AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition( 234 aspectElement, aspectId, beanDefinitions, beanReferences, parserContext); 235 parserContext.pushContainingComponent(aspectComponentDefinition); 236 237 List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT); 238 for (Element pointcutElement : pointcuts) { 239 parsePointcut(pointcutElement, parserContext); 240 } 241 242 parserContext.popAndRegisterContainingComponent(); 243 } 244 finally { 245 this.parseState.pop(); 246 } 247 } 248 createAspectComponentDefinition( Element aspectElement, String aspectId, List<BeanDefinition> beanDefs, List<BeanReference> beanRefs, ParserContext parserContext)249 private AspectComponentDefinition createAspectComponentDefinition( 250 Element aspectElement, String aspectId, List<BeanDefinition> beanDefs, 251 List<BeanReference> beanRefs, ParserContext parserContext) { 252 253 BeanDefinition[] beanDefArray = beanDefs.toArray(new BeanDefinition[beanDefs.size()]); 254 BeanReference[] beanRefArray = beanRefs.toArray(new BeanReference[beanRefs.size()]); 255 Object source = parserContext.extractSource(aspectElement); 256 return new AspectComponentDefinition(aspectId, beanDefArray, beanRefArray, source); 257 } 258 259 /** 260 * Return <code>true</code> if the supplied node describes an advice type. May be one of: 261 * '<code>before</code>', '<code>after</code>', '<code>after-returning</code>', 262 * '<code>after-throwing</code>' or '<code>around</code>'. 263 */ isAdviceNode(Node aNode, ParserContext parserContext)264 private boolean isAdviceNode(Node aNode, ParserContext parserContext) { 265 if (!(aNode instanceof Element)) { 266 return false; 267 } 268 else { 269 String name = parserContext.getDelegate().getLocalName(aNode); 270 return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) || 271 AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name)); 272 } 273 } 274 275 /** 276 * Parse a '<code>declare-parents</code>' element and register the appropriate 277 * DeclareParentsAdvisor with the BeanDefinitionRegistry encapsulated in the 278 * supplied ParserContext. 279 */ parseDeclareParents(Element declareParentsElement, ParserContext parserContext)280 private AbstractBeanDefinition parseDeclareParents(Element declareParentsElement, ParserContext parserContext) { 281 BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(DeclareParentsAdvisor.class); 282 builder.addConstructorArgValue(declareParentsElement.getAttribute(IMPLEMENT_INTERFACE)); 283 builder.addConstructorArgValue(declareParentsElement.getAttribute(TYPE_PATTERN)); 284 285 String defaultImpl = declareParentsElement.getAttribute(DEFAULT_IMPL); 286 String delegateRef = declareParentsElement.getAttribute(DELEGATE_REF); 287 288 if (StringUtils.hasText(defaultImpl) && !StringUtils.hasText(delegateRef)) { 289 builder.addConstructorArgValue(defaultImpl); 290 } 291 else if (StringUtils.hasText(delegateRef) && !StringUtils.hasText(defaultImpl)) { 292 builder.addConstructorArgReference(delegateRef); 293 } 294 else { 295 parserContext.getReaderContext().error( 296 "Exactly one of the " + DEFAULT_IMPL + " or " + DELEGATE_REF + " attributes must be specified", 297 declareParentsElement, this.parseState.snapshot()); 298 } 299 300 AbstractBeanDefinition definition = builder.getBeanDefinition(); 301 definition.setSource(parserContext.extractSource(declareParentsElement)); 302 parserContext.getReaderContext().registerWithGeneratedName(definition); 303 return definition; 304 } 305 306 /** 307 * Parses one of '<code>before</code>', '<code>after</code>', '<code>after-returning</code>', 308 * '<code>after-throwing</code>' or '<code>around</code>' and registers the resulting 309 * BeanDefinition with the supplied BeanDefinitionRegistry. 310 * @return the generated advice RootBeanDefinition 311 */ parseAdvice( String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext, List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences)312 private AbstractBeanDefinition parseAdvice( 313 String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext, 314 List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) { 315 316 try { 317 this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement))); 318 319 // create the method factory bean 320 RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class); 321 methodDefinition.getPropertyValues().add("targetBeanName", aspectName); 322 methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method")); 323 methodDefinition.setSynthetic(true); 324 325 // create instance factory definition 326 RootBeanDefinition aspectFactoryDef = 327 new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class); 328 aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName); 329 aspectFactoryDef.setSynthetic(true); 330 331 // register the pointcut 332 AbstractBeanDefinition adviceDef = createAdviceDefinition( 333 adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef, 334 beanDefinitions, beanReferences); 335 336 // configure the advisor 337 RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class); 338 advisorDefinition.setSource(parserContext.extractSource(adviceElement)); 339 advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef); 340 if (aspectElement.hasAttribute(ORDER_PROPERTY)) { 341 advisorDefinition.getPropertyValues().add( 342 ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY)); 343 } 344 345 // register the final advisor 346 parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition); 347 348 return advisorDefinition; 349 } 350 finally { 351 this.parseState.pop(); 352 } 353 } 354 355 /** 356 * Creates the RootBeanDefinition for a POJO advice bean. Also causes pointcut 357 * parsing to occur so that the pointcut may be associate with the advice bean. 358 * This same pointcut is also configured as the pointcut for the enclosing 359 * Advisor definition using the supplied MutablePropertyValues. 360 */ createAdviceDefinition( Element adviceElement, ParserContext parserContext, String aspectName, int order, RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef, List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences)361 private AbstractBeanDefinition createAdviceDefinition( 362 Element adviceElement, ParserContext parserContext, String aspectName, int order, 363 RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef, 364 List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) { 365 366 RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext)); 367 adviceDefinition.setSource(parserContext.extractSource(adviceElement)); 368 369 adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName); 370 adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order); 371 372 if (adviceElement.hasAttribute(RETURNING)) { 373 adviceDefinition.getPropertyValues().add( 374 RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING)); 375 } 376 if (adviceElement.hasAttribute(THROWING)) { 377 adviceDefinition.getPropertyValues().add( 378 THROWING_PROPERTY, adviceElement.getAttribute(THROWING)); 379 } 380 if (adviceElement.hasAttribute(ARG_NAMES)) { 381 adviceDefinition.getPropertyValues().add( 382 ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES)); 383 } 384 385 ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues(); 386 cav.addIndexedArgumentValue(METHOD_INDEX, methodDef); 387 388 Object pointcut = parsePointcutProperty(adviceElement, parserContext); 389 if (pointcut instanceof BeanDefinition) { 390 cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut); 391 beanDefinitions.add((BeanDefinition) pointcut); 392 } 393 else if (pointcut instanceof String) { 394 RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut); 395 cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef); 396 beanReferences.add(pointcutRef); 397 } 398 399 cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef); 400 401 return adviceDefinition; 402 } 403 404 /** 405 * Gets the advice implementation class corresponding to the supplied {@link Element}. 406 */ getAdviceClass(Element adviceElement, ParserContext parserContext)407 private Class getAdviceClass(Element adviceElement, ParserContext parserContext) { 408 String elementName = parserContext.getDelegate().getLocalName(adviceElement); 409 if (BEFORE.equals(elementName)) { 410 return AspectJMethodBeforeAdvice.class; 411 } 412 else if (AFTER.equals(elementName)) { 413 return AspectJAfterAdvice.class; 414 } 415 else if (AFTER_RETURNING_ELEMENT.equals(elementName)) { 416 return AspectJAfterReturningAdvice.class; 417 } 418 else if (AFTER_THROWING_ELEMENT.equals(elementName)) { 419 return AspectJAfterThrowingAdvice.class; 420 } 421 else if (AROUND.equals(elementName)) { 422 return AspectJAroundAdvice.class; 423 } 424 else { 425 throw new IllegalArgumentException("Unknown advice kind [" + elementName + "]."); 426 } 427 } 428 429 /** 430 * Parses the supplied <code><pointcut></code> and registers the resulting 431 * Pointcut with the BeanDefinitionRegistry. 432 */ parsePointcut(Element pointcutElement, ParserContext parserContext)433 private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) { 434 String id = pointcutElement.getAttribute(ID); 435 String expression = pointcutElement.getAttribute(EXPRESSION); 436 437 AbstractBeanDefinition pointcutDefinition = null; 438 439 try { 440 this.parseState.push(new PointcutEntry(id)); 441 pointcutDefinition = createPointcutDefinition(expression); 442 pointcutDefinition.setSource(parserContext.extractSource(pointcutElement)); 443 444 String pointcutBeanName = id; 445 if (StringUtils.hasText(pointcutBeanName)) { 446 parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition); 447 } 448 else { 449 pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition); 450 } 451 452 parserContext.registerComponent( 453 new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression)); 454 } 455 finally { 456 this.parseState.pop(); 457 } 458 459 return pointcutDefinition; 460 } 461 462 /** 463 * Parses the <code>pointcut</code> or <code>pointcut-ref</code> attributes of the supplied 464 * {@link Element} and add a <code>pointcut</code> property as appropriate. Generates a 465 * {@link org.springframework.beans.factory.config.BeanDefinition} for the pointcut if necessary 466 * and returns its bean name, otherwise returns the bean name of the referred pointcut. 467 */ parsePointcutProperty(Element element, ParserContext parserContext)468 private Object parsePointcutProperty(Element element, ParserContext parserContext) { 469 if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) { 470 parserContext.getReaderContext().error( 471 "Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.", 472 element, this.parseState.snapshot()); 473 return null; 474 } 475 else if (element.hasAttribute(POINTCUT)) { 476 // Create a pointcut for the anonymous pc and register it. 477 String expression = element.getAttribute(POINTCUT); 478 AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression); 479 pointcutDefinition.setSource(parserContext.extractSource(element)); 480 return pointcutDefinition; 481 } 482 else if (element.hasAttribute(POINTCUT_REF)) { 483 String pointcutRef = element.getAttribute(POINTCUT_REF); 484 if (!StringUtils.hasText(pointcutRef)) { 485 parserContext.getReaderContext().error( 486 "'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot()); 487 return null; 488 } 489 return pointcutRef; 490 } 491 else { 492 parserContext.getReaderContext().error( 493 "Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.", 494 element, this.parseState.snapshot()); 495 return null; 496 } 497 } 498 499 /** 500 * Creates a {@link BeanDefinition} for the {@link AspectJExpressionPointcut} class using 501 * the supplied pointcut expression. 502 */ createPointcutDefinition(String expression)503 protected AbstractBeanDefinition createPointcutDefinition(String expression) { 504 RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class); 505 beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE); 506 beanDefinition.setSynthetic(true); 507 beanDefinition.getPropertyValues().add(EXPRESSION, expression); 508 return beanDefinition; 509 } 510 511 } 512