這幾個接口實際獲取的對象都是從當前線程的上下文中獲取的(通過ThreadLocal),所以在Controller中直接屬性注入相應的對象是線程安全的。
1 接口對比
ObjectFactory
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
就是一個普通的函數式對象接口。
FactoryBean
public interface FactoryBean<T> {
// 返回真實的對象
T getObject() throws Exception;
// 返回對象類型
Class<?> getObjectType();
// 是否單例;如果是單例會將其創建的對象緩存到緩存池中。
boolean isSingleton();
}
該接口就是一個工廠Bean,在獲取對象時,先判斷當前對象是否是FactoryBean,如果是再根據getObjectType的返回類型判斷是否需要的類型,如果匹配則會調用getObject方法返回真實的對象。該接口用來自定義對象的創建。
注意:如果A.class 實現了FactoryBean,如果想獲取A本身這個對象則bean的名稱必須添加前綴 '&',也就是獲取Bean則需要ctx.getBean("&a")
當注入屬性是ObjectFactory或者ObjectProvider類型時,系統會直接創建DependencyObjectProvider對象然后進行注入,只有在真正調用getObject方法的時候系統才會根據字段上的泛型類型進行查找注入。
2 實際應用
ObjectFactory在Spring源碼中應用的比較多
2.1 創建Bean實例
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方法的第二個參數就是ObjectFactory對象(這里應用了lamda表達式)
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)創建Bean;具體的創建細節都是交個ObjectFactory來完成。
2.2 Servlet API注入
在Controller中注入Request,Response相關對象時也是通過ObjectFactory接口。
容器啟動時實例化的上下文對象是AnnotationConfigServletWebServerApplicationContext;
調用在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)方法進入到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接口。
這幾個接口實際獲取的對象都是從當前線程的上下文中獲取的(通過ThreadLocal),所以在Controller中直接屬性注入相應的對象是線程安全的。
注意:這里registerResolvableDependency方法意圖就是當有Bean需要注入相應的Request,Response對象時直接注入第二個參數的值即可。
2.3 自定義定義ObjectFactory
在IOC容器,如果有兩個相同類型的Bean,這時候在注入的時候肯定是會報錯的,示例如下:
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 ;
}
當我們有如上的Bean后,啟動容器會報錯如下:
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]
期望一個AccountDAO類型的Bean,但當前環境卻有兩個。
解決這個辦法可以通過@Primary和@Qualifier來解決,這兩個方法這里不做介紹;接下來我們通過BeanFactory#registerResolvableDependency的方式來解決;
自定義BeanFactoryPostProcessor
// 方式1:直接通過beanFactory獲取指定的bean注入。
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// beanFactory的實例是DefaultListableBeanFactory,該實例內部維護了一個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() ;
}
}
// 對應的BeanFactoryPostProcessor
beanFactory.registerResolvableDependency(AccountDAO.class, new AccountObjectFactory());
當一個Bean的屬性在填充(注入)時調用AbstractAutowireCapableBeanFactory.populateBean方法時,會在當前的IOC容器中查找符合的Bean,最終執行如下方法:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
protected Map<String, Object> findAutowireCandidates(@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 從當前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();
// 解析自動裝配的類型值(主要就是判斷當前的值對象是否是ObjectFactory對象)
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
// 要注意這里,如果通過registerResolvableDependency添加的對象是個ObjectFactory,那么最終會調用factory.getObject方法返回真實的對象并且加入到result集合中。這時候相當于當前類型還是找到了多個Bean還是會報錯。
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方法
// 該方法中會判斷對象是否是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 {
// 進入這里之間調用getObject返回對象
return factory.getObject();
}
}
return autowiringValue;
}
完畢!!!