001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.aop.framework.autoproxy; 018 019import java.util.ArrayList; 020import java.util.List; 021 022import org.apache.commons.logging.Log; 023import org.apache.commons.logging.LogFactory; 024 025import org.springframework.aop.Advisor; 026import org.springframework.beans.factory.BeanCreationException; 027import org.springframework.beans.factory.BeanCurrentlyInCreationException; 028import org.springframework.beans.factory.BeanFactoryUtils; 029import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 030import org.springframework.util.Assert; 031 032/** 033 * Helper for retrieving standard Spring Advisors from a BeanFactory, 034 * for use with auto-proxying. 035 * 036 * @author Juergen Hoeller 037 * @since 2.0.2 038 * @see AbstractAdvisorAutoProxyCreator 039 */ 040public class BeanFactoryAdvisorRetrievalHelper { 041 042 private static final Log logger = LogFactory.getLog(BeanFactoryAdvisorRetrievalHelper.class); 043 044 private final ConfigurableListableBeanFactory beanFactory; 045 046 private volatile String[] cachedAdvisorBeanNames; 047 048 049 /** 050 * Create a new BeanFactoryAdvisorRetrievalHelper for the given BeanFactory. 051 * @param beanFactory the ListableBeanFactory to scan 052 */ 053 public BeanFactoryAdvisorRetrievalHelper(ConfigurableListableBeanFactory beanFactory) { 054 Assert.notNull(beanFactory, "ListableBeanFactory must not be null"); 055 this.beanFactory = beanFactory; 056 } 057 058 059 /** 060 * Find all eligible Advisor beans in the current bean factory, 061 * ignoring FactoryBeans and excluding beans that are currently in creation. 062 * @return the list of {@link org.springframework.aop.Advisor} beans 063 * @see #isEligibleBean 064 */ 065 public List<Advisor> findAdvisorBeans() { 066 // Determine list of advisor bean names, if not cached already. 067 String[] advisorNames = this.cachedAdvisorBeanNames; 068 if (advisorNames == null) { 069 // Do not initialize FactoryBeans here: We need to leave all regular beans 070 // uninitialized to let the auto-proxy creator apply to them! 071 advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( 072 this.beanFactory, Advisor.class, true, false); 073 this.cachedAdvisorBeanNames = advisorNames; 074 } 075 if (advisorNames.length == 0) { 076 return new ArrayList<Advisor>(); 077 } 078 079 List<Advisor> advisors = new ArrayList<Advisor>(); 080 for (String name : advisorNames) { 081 if (isEligibleBean(name)) { 082 if (this.beanFactory.isCurrentlyInCreation(name)) { 083 if (logger.isDebugEnabled()) { 084 logger.debug("Skipping currently created advisor '" + name + "'"); 085 } 086 } 087 else { 088 try { 089 advisors.add(this.beanFactory.getBean(name, Advisor.class)); 090 } 091 catch (BeanCreationException ex) { 092 Throwable rootCause = ex.getMostSpecificCause(); 093 if (rootCause instanceof BeanCurrentlyInCreationException) { 094 BeanCreationException bce = (BeanCreationException) rootCause; 095 if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) { 096 if (logger.isDebugEnabled()) { 097 logger.debug("Skipping advisor '" + name + 098 "' with dependency on currently created bean: " + ex.getMessage()); 099 } 100 // Ignore: indicates a reference back to the bean we're trying to advise. 101 // We want to find advisors other than the currently created bean itself. 102 continue; 103 } 104 } 105 throw ex; 106 } 107 } 108 } 109 } 110 return advisors; 111 } 112 113 /** 114 * Determine whether the aspect bean with the given name is eligible. 115 * <p>The default implementation always returns {@code true}. 116 * @param beanName the name of the aspect bean 117 * @return whether the bean is eligible 118 */ 119 protected boolean isEligibleBean(String beanName) { 120 return true; 121 } 122 123}