All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.taketoday.aop.framework.autoproxy.BeanFactoryAdvisorRetriever Maven / Gradle / Ivy

/*
 * Original Author -> Harry Yang ([email protected]) https://taketoday.cn
 * Copyright © TODAY & 2017 - 2021 All Rights Reserved.
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see [http://www.gnu.org/licenses/]
 */

package cn.taketoday.aop.framework.autoproxy;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import cn.taketoday.aop.Advisor;
import cn.taketoday.beans.factory.BeanCreationException;
import cn.taketoday.beans.factory.BeanCurrentlyInCreationException;
import cn.taketoday.beans.factory.BeanFactoryUtils;
import cn.taketoday.beans.factory.config.ConfigurableBeanFactory;
import cn.taketoday.lang.Assert;
import cn.taketoday.lang.Nullable;
import cn.taketoday.logging.Logger;
import cn.taketoday.logging.LoggerFactory;

/**
 * Helper for retrieving standard Framework Advisors from a BeanFactory,
 * for use with auto-proxying.
 *
 * @author Juergen Hoeller
 * @author Harry Yang
 * @see AbstractAdvisorAutoProxyCreator
 * @since 4.0
 */
public class BeanFactoryAdvisorRetriever {
  private static final Logger logger = LoggerFactory.getLogger(BeanFactoryAdvisorRetriever.class);

  private final ConfigurableBeanFactory beanFactory;

  @Nullable
  private volatile Set cachedAdvisorBeanNames;

  /**
   * Create a new BeanFactoryAdvisorRetrievalHelper for the given BeanFactory.
   *
   * @param beanFactory the BeanFactory to scan
   */
  public BeanFactoryAdvisorRetriever(ConfigurableBeanFactory beanFactory) {
    Assert.notNull(beanFactory, "ConfigurableBeanFactory is required");
    this.beanFactory = beanFactory;
  }

  /**
   * Find all eligible Advisor beans in the current bean factory,
   * ignoring FactoryBeans and excluding beans that are currently in creation.
   *
   * @return the list of {@link Advisor} beans
   * @see #isEligibleBean
   */
  public List retrieveAdvisorBeans() {
    // Determine list of advisor bean names, if not cached already.
    Set advisorNames = this.cachedAdvisorBeanNames;
    if (advisorNames == null) {
      // Do not initialize FactoryBeans here: We need to leave all regular beans
      // uninitialized to let the auto-proxy creator apply to them!
      advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
              beanFactory, Advisor.class, true, false);
      this.cachedAdvisorBeanNames = advisorNames;
    }
    if (advisorNames.isEmpty()) {
      return new ArrayList<>();
    }

    ArrayList advisors = new ArrayList<>();
    for (String name : advisorNames) {
      if (isEligibleBean(name)) {
        if (beanFactory.isCurrentlyInCreation(name)) {
          if (logger.isTraceEnabled()) {
            logger.trace("Skipping currently created advisor '{}'", name);
          }
        }
        else {
          try {
            advisors.add(beanFactory.getBean(name, Advisor.class));
          }
          catch (BeanCreationException ex) {
            Throwable rootCause = ex.getMostSpecificCause();
            if (rootCause instanceof BeanCurrentlyInCreationException bce) {
              String bceBeanName = bce.getBeanName();
              if (bceBeanName != null && beanFactory.isCurrentlyInCreation(bceBeanName)) {
                if (logger.isTraceEnabled()) {
                  logger.trace("Skipping advisor '{}' with dependency on currently created bean: {}",
                          name, ex.getMessage());
                }
                // Ignore: indicates a reference back to the bean we're trying to advise.
                // We want to find advisors other than the currently created bean itself.
                continue;
              }
            }
            throw ex;
          }
        }
      }
    }
    return advisors;
  }

  /**
   * Determine whether the aspect bean with the given name is eligible.
   * 

The default implementation always returns {@code true}. * * @param beanName the name of the aspect bean * @return whether the bean is eligible */ protected boolean isEligibleBean(String beanName) { return true; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy