1 16 17 package org.springframework.aop.framework; 18 19 import java.util.ArrayList ; 20 import java.util.Collections ; 21 import java.util.HashMap ; 22 import java.util.Iterator ; 23 import java.util.List ; 24 import java.util.Map ; 25 26 import org.aopalliance.aop.Advice; 27 import org.aopalliance.intercept.Interceptor; 28 import org.apache.commons.logging.Log; 29 import org.apache.commons.logging.LogFactory; 30 31 import org.springframework.aop.Advisor; 32 import org.springframework.aop.TargetSource; 33 import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry; 34 import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry; 35 import org.springframework.aop.framework.adapter.UnknownAdviceTypeException; 36 import org.springframework.aop.target.SingletonTargetSource; 37 import org.springframework.beans.BeansException; 38 import org.springframework.beans.factory.BeanClassLoaderAware; 39 import org.springframework.beans.factory.BeanFactory; 40 import org.springframework.beans.factory.BeanFactoryAware; 41 import org.springframework.beans.factory.BeanFactoryUtils; 42 import org.springframework.beans.factory.FactoryBean; 43 import org.springframework.beans.factory.ListableBeanFactory; 44 import org.springframework.core.OrderComparator; 45 import org.springframework.util.ClassUtils; 46 import org.springframework.util.ObjectUtils; 47 48 88 public class ProxyFactoryBean extends ProxyCreatorSupport 89 implements FactoryBean, BeanClassLoaderAware, BeanFactoryAware { 90 91 94 public static final String GLOBAL_SUFFIX = "*"; 95 96 97 protected final Log logger = LogFactory.getLog(getClass()); 98 99 private String [] interceptorNames; 100 101 private String targetName; 102 103 private boolean autodetectInterfaces = true; 104 105 private boolean singleton = true; 106 107 private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance(); 108 109 112 private boolean freezeProxy = false; 113 114 private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); 115 116 120 private BeanFactory beanFactory; 121 122 123 private boolean advisorChainInitialized = false; 124 125 126 private Object singletonInstance; 127 128 129 137 public void setProxyInterfaces(Class [] proxyInterfaces) throws ClassNotFoundException { 138 setInterfaces(proxyInterfaces); 139 } 140 141 155 public void setInterceptorNames(String [] interceptorNames) { 156 this.interceptorNames = interceptorNames; 157 } 158 159 168 public void setTargetName(String targetName) { 169 this.targetName = targetName; 170 } 171 172 178 public void setAutodetectInterfaces(boolean autodetectInterfaces) { 179 this.autodetectInterfaces = autodetectInterfaces; 180 } 181 182 190 public void setSingleton(boolean singleton) { 191 this.singleton = singleton; 192 } 193 194 199 public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) { 200 this.advisorAdapterRegistry = advisorAdapterRegistry; 201 } 202 203 public void setFrozen(boolean frozen) { 204 this.freezeProxy = frozen; 205 } 206 207 public void setBeanClassLoader(ClassLoader classLoader) { 208 this.beanClassLoader = classLoader; 209 } 210 211 public void setBeanFactory(BeanFactory beanFactory) { 212 this.beanFactory = beanFactory; 213 checkInterceptorNames(); 214 } 215 216 217 224 public Object getObject() throws BeansException { 225 initializeAdvisorChain(); 226 if (isSingleton()) { 227 return getSingletonInstance(); 228 } 229 else { 230 if (this.targetName == null) { 231 logger.warn("Using non-singleton proxies with singleton targets is often undesirable." + 232 "Enable prototype proxies by setting the 'targetName' property."); 233 } 234 return newPrototypeInstance(); 235 } 236 } 237 238 244 public Class getObjectType() { 245 synchronized (this) { 246 if (this.singletonInstance != null) { 247 return this.singletonInstance.getClass(); 248 } 249 } 250 Class [] ifcs = getProxiedInterfaces(); 251 if (ifcs.length == 1) { 252 return ifcs[0]; 253 } 254 else if (ifcs.length > 1) { 255 return createCompositeInterface(ifcs); 256 } 257 else if (this.targetName != null && this.beanFactory != null) { 258 return this.beanFactory.getType(this.targetName); 259 } 260 else { 261 return getTargetClass(); 262 } 263 } 264 265 public boolean isSingleton() { 266 return this.singleton; 267 } 268 269 270 279 protected Class createCompositeInterface(Class [] interfaces) { 280 return ClassUtils.createCompositeInterface(interfaces, this.beanClassLoader); 281 } 282 283 288 private synchronized Object getSingletonInstance() { 289 if (this.singletonInstance == null) { 290 this.targetSource = freshTargetSource(); 291 if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { 292 setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass())); 294 } 295 super.setFrozen(this.freezeProxy); 297 this.singletonInstance = getProxy(createAopProxy()); 298 } 299 return this.singletonInstance; 300 } 301 302 307 private synchronized Object newPrototypeInstance() { 308 if (logger.isTraceEnabled()) { 313 logger.trace("Creating copy of prototype ProxyFactoryBean config: " + this); 314 } 315 316 ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory()); 317 TargetSource targetSource = freshTargetSource(); 319 copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain()); 320 if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { 321 copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass())); 323 } 324 copy.setFrozen(this.freezeProxy); 325 326 if (logger.isTraceEnabled()) { 327 logger.trace("Using ProxyCreatorSupport copy: " + copy); 328 } 329 return getProxy(copy.createAopProxy()); 330 } 331 332 341 protected Object getProxy(AopProxy aopProxy) { 342 return aopProxy.getProxy(this.beanClassLoader); 343 } 344 345 349 private void checkInterceptorNames() { 350 if (!ObjectUtils.isEmpty(this.interceptorNames)) { 351 String finalName = this.interceptorNames[this.interceptorNames.length - 1]; 352 if (this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) { 353 if (!finalName.endsWith(GLOBAL_SUFFIX) && !isNamedBeanAnAdvisorOrAdvice(finalName)) { 356 this.targetName = finalName; 358 if (logger.isDebugEnabled()) { 359 logger.debug("Bean with name '" + finalName + "' concluding interceptor chain " + 360 "is not an advisor class: treating it as a target or TargetSource"); 361 } 362 String [] newNames = new String [this.interceptorNames.length - 1]; 363 System.arraycopy(this.interceptorNames, 0, newNames, 0, newNames.length); 364 this.interceptorNames = newNames; 365 } 366 } 367 } 368 } 369 370 377 private boolean isNamedBeanAnAdvisorOrAdvice(String beanName) { 378 Class namedBeanClass = this.beanFactory.getType(beanName); 379 if (namedBeanClass != null) { 380 return Advisor.class.isAssignableFrom(namedBeanClass) || 381 Advice.class.isAssignableFrom(namedBeanClass); 382 } 383 return true; 385 } 386 387 393 private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { 394 if (this.advisorChainInitialized) { 395 return; 396 } 397 398 if (!ObjectUtils.isEmpty(this.interceptorNames)) { 399 400 if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) && 402 this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) { 403 throw new AopConfigException("Target required after globals"); 404 } 405 406 for (int i = 0; i < this.interceptorNames.length; i++) { 408 String name = this.interceptorNames[i]; 409 if (logger.isTraceEnabled()) { 410 logger.trace("Configuring advisor or advice '" + name + "'"); 411 } 412 413 if (name.endsWith(GLOBAL_SUFFIX)) { 414 if (!(this.beanFactory instanceof ListableBeanFactory)) { 415 throw new AopConfigException( 416 "Can only use global advisors or interceptors with a ListableBeanFactory"); 417 } 418 addGlobalAdvisor((ListableBeanFactory) this.beanFactory, 419 name.substring(0, name.length() - GLOBAL_SUFFIX.length())); 420 } 421 422 else { 423 Object advice = null; 426 if (this.singleton || this.beanFactory.isSingleton(this.interceptorNames[i])) { 427 advice = this.beanFactory.getBean(this.interceptorNames[i]); 429 } 430 else { 431 advice = new PrototypePlaceholderAdvisor(interceptorNames[i]); 434 } 435 addAdvisorOnChainCreation(advice, this.interceptorNames[i]); 436 } 437 } 438 } 439 440 this.advisorChainInitialized = true; 441 } 442 443 444 449 private List freshAdvisorChain() { 450 Advisor[] advisors = getAdvisors(); 451 List freshAdvisors = new ArrayList (advisors.length); 452 453 for (int i = 0; i < advisors.length; i++) { 454 if (advisors[i] instanceof PrototypePlaceholderAdvisor) { 455 PrototypePlaceholderAdvisor pa = (PrototypePlaceholderAdvisor) advisors[i]; 456 if (logger.isDebugEnabled()) { 457 logger.debug("Refreshing bean named '" + pa.getBeanName() + "'"); 458 } 459 Object bean = this.beanFactory.getBean(pa.getBeanName()); 462 Advisor refreshedAdvisor = namedBeanToAdvisor(bean); 463 freshAdvisors.add(refreshedAdvisor); 464 } 465 else { 466 freshAdvisors.add(advisors[i]); 468 } 469 } 470 return freshAdvisors; 471 } 472 473 476 private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) { 477 String [] globalAdvisorNames = 478 BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class); 479 String [] globalInterceptorNames = 480 BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Interceptor.class); 481 List beans = new ArrayList (globalAdvisorNames.length + globalInterceptorNames.length); 482 Map names = new HashMap (); 483 for (int i = 0; i < globalAdvisorNames.length; i++) { 484 String name = globalAdvisorNames[i]; 485 Object bean = beanFactory.getBean(name); 486 beans.add(bean); 487 names.put(bean, name); 488 } 489 for (int i = 0; i < globalInterceptorNames.length; i++) { 490 String name = globalInterceptorNames[i]; 491 Object bean = beanFactory.getBean(name); 492 beans.add(bean); 493 names.put(bean, name); 494 } 495 Collections.sort(beans, new OrderComparator()); 496 for (Iterator it = beans.iterator(); it.hasNext();) { 497 Object bean = it.next(); 498 String name = (String ) names.get(bean); 499 if (name.startsWith(prefix)) { 500 addAdvisorOnChainCreation(bean, name); 501 } 502 } 503 } 504 505 514 private void addAdvisorOnChainCreation(Object next, String name) { 515 Advisor advisor = namedBeanToAdvisor(next); 518 if (logger.isTraceEnabled()) { 519 logger.trace("Adding advisor with name '" + name + "'"); 520 } 521 addAdvisor((Advisor) advisor); 522 } 523 524 530 private TargetSource freshTargetSource() { 531 if (this.targetName == null) { 532 if (logger.isTraceEnabled()) { 533 logger.trace("Not refreshing target: Bean name not specified in 'interceptorNames'."); 534 } 535 return this.targetSource; 536 } 537 else { 538 if (logger.isDebugEnabled()) { 539 logger.debug("Refreshing target with name '" + this.targetName + "'"); 540 } 541 Object target = this.beanFactory.getBean(this.targetName); 542 return (target instanceof TargetSource ? (TargetSource) target : new SingletonTargetSource(target)); 543 } 544 } 545 546 550 private Advisor namedBeanToAdvisor(Object next) { 551 try { 552 return this.advisorAdapterRegistry.wrap(next); 553 } 554 catch (UnknownAdviceTypeException ex) { 555 throw new AopConfigException("Unknown advisor type " + next.getClass() + 558 "; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry," + 559 "which may also be target or TargetSource", ex); 560 } 561 } 562 563 566 protected void adviceChanged() { 567 super.adviceChanged(); 568 if (this.singleton) { 569 logger.debug("Advice has changed; recaching singleton instance"); 570 synchronized (this) { 571 this.singletonInstance = null; 572 } 573 } 574 } 575 576 577 581 private static class PrototypePlaceholderAdvisor implements Advisor { 582 583 private final String beanName; 584 585 private final String message; 586 587 public PrototypePlaceholderAdvisor(String beanName) { 588 this.beanName = beanName; 589 this.message = "Placeholder for prototype Advisor/Advice with bean name '" + beanName + "'"; 590 } 591 592 public String getBeanName() { 593 return beanName; 594 } 595 596 public Advice getAdvice() { 597 throw new UnsupportedOperationException ("Cannot invoke methods: " + this.message); 598 } 599 600 public boolean isPerInstance() { 601 throw new UnsupportedOperationException ("Cannot invoke methods: " + this.message); 602 } 603 604 public String toString() { 605 return this.message; 606 } 607 } 608 609 } 610 | Popular Tags |