1 接口对比
ObjectFactory
@FunctionalInterface
public interface ObjectFactory {
T getObject() throws BeansException;
}
就是一个普通的函数式对象接口。
FactoryBean
public interface FactoryBean {
// 返回真实的对象
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 doGetBean(String name, @Nullable Class 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 {
@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 findAutowireCandidates(@Nullable String beanName, Class requiredType, DependencyDescriptor descriptor) {
// 从当前IOC容器中查找所有指定类型的Bean
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());
Map result = new LinkedHashMap(candidateNames.length);
// 遍历DefaultListableBeanFactory对象中通过registerResolvableDependency方法注册的
for (Map.Entry 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;
}
完毕!!!