亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

這幾個(gè)接口實(shí)際獲取的對象都是從當(dāng)前線程的上下文中獲取的(通過ThreadLocal),所以在Controller中直接屬性注入相應(yīng)的對象是線程安全的。

1 接口對比

ObjectFactory

@FunctionalInterface
public interface ObjectFactory<T> {


 T getObject() throws BeansException;


}

就是一個(gè)普通的函數(shù)式對象接口。

FactoryBean

public interface FactoryBean<T> {
 // 返回真實(shí)的對象
 T getObject() throws Exception;
 // 返回對象類型
 Class<?> getObjectType();
 // 是否單例;如果是單例會(huì)將其創(chuàng)建的對象緩存到緩存池中。
 boolean isSingleton();
}

該接口就是一個(gè)工廠Bean,在獲取對象時(shí),先判斷當(dāng)前對象是否是FactoryBean,如果是再根據(jù)getObjectType的返回類型判斷是否需要的類型,如果匹配則會(huì)調(diào)用getObject方法返回真實(shí)的對象。該接口用來自定義對象的創(chuàng)建。

注意:如果A.class 實(shí)現(xiàn)了FactoryBean,如果想獲取A本身這個(gè)對象則bean的名稱必須添加前綴 '&',也就是獲取Bean則需要ctx.getBean("&a")

當(dāng)注入屬性是ObjectFactory或者ObjectProvider類型時(shí),系統(tǒng)會(huì)直接創(chuàng)建DependencyObjectProvider對象然后進(jìn)行注入,只有在真正調(diào)用getObject方法的時(shí)候系統(tǒng)才會(huì)根據(jù)字段上的泛型類型進(jìn)行查找注入。

2 實(shí)際應(yīng)用

ObjectFactory在Spring源碼中應(yīng)用的比較多

2.1 創(chuàng)建Bean實(shí)例

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
  protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
    // other code  
    if (mbd.isSingleton()) {
      //getSingleton方法的第二個(gè)參數(shù)就是ObjectFactory對象(這里應(yīng)用了lamda表達(dá)式)
      sharedInstance = getSingleton(beanName, () -> {
        try {
          return createBean(beanName, mbd, args);
        } catch (BeansException ex) {
          // Explicitly remove instance from singleton cache: It might have been put there
          // eagerly by the creation process, to allow for circular reference resolution.
          // Also remove any beans that received a temporary reference to the bean.
          destroySingleton(beanName);
          throw ex;
        }
      });
      beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
    // other code  
  }
}

這里的getSingleton方法就是通過不同的Scope(singleton,prototype,request,session)創(chuàng)建Bean;具體的創(chuàng)建細(xì)節(jié)都是交個(gè)ObjectFactory來完成。

2.2 Servlet API注入

在Controller中注入Request,Response相關(guān)對象時(shí)也是通過ObjectFactory接口。

容器啟動(dòng)時(shí)實(shí)例化的上下文對象是AnnotationConfigServletWebServerApplicationContext;

調(diào)用在AbstractApplicationContext#refresh.postProcessBeanFactory

public class AnnotationConfigServletWebServerApplicationContext {
  protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    super.postProcessBeanFactory(beanFactory);
    if (this.basePackages != null && this.basePackages.length > 0) {
      this.scanner.scan(this.basePackages);
    }
    if (!this.annotatedClasses.isEmpty()) {
      this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
    }
  }    
}

super.postProcessBeanFactory(beanFactory)方法進(jìn)入到ServletWebServerApplicationContext中

public class ServletWebServerApplicationContext extends GenericWebApplicationContext implements ConfigurableWebServerApplicationContext {
  @Override
  protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
    beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    registerWebApplicationScopes();
  }
  private void registerWebApplicationScopes() {
    ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory());
    WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
    existingScopes.restore();
  }
}

WebApplicationContextUtils工具類

public abstract class WebApplicationContextUtils {
    
  public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
    registerWebApplicationScopes(beanFactory, null);
  }
  public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, @Nullable ServletContext sc) {
    beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
    beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
    if (sc != null) {
      ServletContextScope appScope = new ServletContextScope(sc);
      beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
      // Register as ServletContext attribute, for ContextCleanupListener to detect it.
      sc.setAttribute(ServletContextScope.class.getName(), appScope);
    }
    beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
    beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseobjectFactory());
    beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
    beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
    if (jsfPresent) {
      FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
    }
  }
}

這里的RequestObjectFactory,ResponseObjectFactory,SessionObjectFactory,WebRequestObjectFactory都是ObjectFactory接口。

這幾個(gè)接口實(shí)際獲取的對象都是從當(dāng)前線程的上下文中獲取的(通過ThreadLocal),所以在Controller中直接屬性注入相應(yīng)的對象是線程安全的。

注意:這里registerResolvableDependency方法意圖就是當(dāng)有Bean需要注入相應(yīng)的Request,Response對象時(shí)直接注入第二個(gè)參數(shù)的值即可。

2.3 自定義定義ObjectFactory

在IOC容器,如果有兩個(gè)相同類型的Bean,這時(shí)候在注入的時(shí)候肯定是會(huì)報(bào)錯(cuò)的,示例如下:

public interface AccountDAO {
}
@Component
public class AccountADAO implements AccountDAO {
}
@Component
public class AccountBDAO implements AccountDAO {
}
@RestController
@RequestMapping("/accounts")
public class AccountController {
  @Resource
  private AccountDAO dao ;
}

當(dāng)我們有如上的Bean后,啟動(dòng)容器會(huì)報(bào)錯(cuò)如下:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.pack.objectfactory.AccountDAO' avAIlable: expected single matching bean but found 2: accountADAO,accountBDAO
  at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.JAVA:220) ~[spring-beans-5.2.13.RELEASE.jar:5.2.13.RELEASE]

期望一個(gè)AccountDAO類型的Bean,但當(dāng)前環(huán)境卻有兩個(gè)。

解決這個(gè)辦法可以通過@Primary和@Qualifier來解決,這兩個(gè)方法這里不做介紹;接下來我們通過BeanFactory#registerResolvableDependency的方式來解決;

自定義BeanFactoryPostProcessor

// 方式1:直接通過beanFactory獲取指定的bean注入。
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    // beanFactory的實(shí)例是DefaultListableBeanFactory,該實(shí)例內(nèi)部維護(hù)了一個(gè)ConcurrentMap resolvableDependencies 的集合,Class作為key。
    beanFactory.registerResolvableDependency(AccountDAO.class, beanFactory.getBean("accountBDAO"));
  }
}

自定義ObjectFactory

public class AccountObjectFactory implements ObjectFactory<AccountDAO> {
  @Override
  public AccountDAO getObject() throws BeansException {
    return new AccountBDAO() ;
  }
}
// 對應(yīng)的BeanFactoryPostProcessor
beanFactory.registerResolvableDependency(AccountDAO.class, new AccountObjectFactory());

當(dāng)一個(gè)Bean的屬性在填充(注入)時(shí)調(diào)用AbstractAutowireCapableBeanFactory.populateBean方法時(shí),會(huì)在當(dāng)前的IOC容器中查找符合的Bean,最終執(zhí)行如下方法:

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
  protected Map<String, Object> findAutowireCandidates(@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
    // 從當(dāng)前IOC容器中查找所有指定類型的Bean  
    String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());
    Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
    // 遍歷DefaultListableBeanFactory對象中通過registerResolvableDependency方法注冊的
    for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
      Class<?> autowiringType = classObjectEntry.getKey();
      if (autowiringType.isAssignableFrom(requiredType)) {
        Object autowiringValue = classObjectEntry.getValue();
        // 解析自動(dòng)裝配的類型值(主要就是判斷當(dāng)前的值對象是否是ObjectFactory對象)  
        autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
        if (requiredType.isInstance(autowiringValue)) {
          // 要注意這里,如果通過registerResolvableDependency添加的對象是個(gè)ObjectFactory,那么最終會(huì)調(diào)用factory.getObject方法返回真實(shí)的對象并且加入到result集合中。這時(shí)候相當(dāng)于當(dāng)前類型還是找到了多個(gè)Bean還是會(huì)報(bào)錯(cuò)。
          result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
          break;
        }
      }
    }
    for (String candidate : candidateNames) {
      if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
        addCandidateEntry(result, candidate, descriptor, requiredType);
      }
    }
    return result;
  }    
}
// AutowireUtils.resolveAutowiringValue方法
// 該方法中會(huì)判斷對象是否是ObjectFactory
public static Object resolveAutowiringValue(Object autowiringValue, Class<?> requiredType) {
  if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
    ObjectFactory<?> factory = (ObjectFactory<?>) autowiringValue;
    if (autowiringValue instanceof Serializable && requiredType.isInterface()) {
      autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(), new Class<?>[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
    } else {
      // 進(jìn)入這里之間調(diào)用getObject返回對象  
      return factory.getObject();
    }
  }
  return autowiringValue;
}

完畢!!!

分享到:
標(biāo)簽:Spring
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評(píng)定2018-06-03

通用課目體育訓(xùn)練成績評(píng)定