FactoryBean的使用
在一般的情况下,spring通过反射机制利用bean的class属性指定实现类来实例化bean。在某些情况下,实例化bean比较复杂,按照传统的方式,则需要在<bean>中提供大量的配置信息,配置方式的灵活性受到限制,这时采用编码的方式可能得到简单的方案。spring为此提供了一个org.springframework.beans.factory.FactoryBean的工厂类接口,用户就可以通过实现该接口来定制实例化bean的逻辑。
其在spring中占有重要地位。它们隐藏了一些实例化过程中复杂的bean的细节,给上层带来便利。
public interface FactoryBean<T> {
/**
返回由FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到spring的容器中单实例缓存池中
*/
T getObject() throws Exception;
/**
*返回Factory Bean创建的bean类型
*/
Class<?> getObjectType();
/**
返回由FactoryBean创建的bean实例的作用域是singleton还是prototype
*/
boolean isSingleton();
例如以下代码示例:
package springSourseAnalyes;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyFactoryBeanTest implements FactoryBean<BeanA>,InitializingBean,BeanPostProcessor{
private String userInfo;
private BeanA a;
public void setUserInfo(String userInfo) {
this.userInfo = userInfo;
}
@Override
public BeanA getObject() throws Exception {
String[] split = userInfo.split(";");
a.setNameString(split[0]);
a.setAge(Integer.parseInt(split[1]));
return a;
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return BeanA.class;
}
/**
* 如果是单例,则放到spring容器的单例缓存中
*/
@Override
public boolean isSingleton() {
return false;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("====调用接口Initialize接口的afterPropertiesSet===实例化bean=========");
a = new BeanA();
//如果afterPropertiesSet方法抛出异常,则xml配置的init-method也不会执行
// throw new Exception();
}
public String getUserInfo() {
return userInfo;
}
void init(){
System.out.println("调用xml配置的init-method属性。。。。。。");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("开始调用postProcessBeforeInitialization。。。。"+bean+":"+beanName);
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("开始调用postProcessAfterInitialization。。。。"+bean+":"+beanName);
return bean;
}
}
xml配置:
<bean id="myBeanFactory" class="springSourseAnalyes.MyFactoryBeanTest" init-method="init" lazy-init="true">
<property name="userInfo" value="fack;20"/>
</bean>
调用:
BeanA bbA = (BeanA) bean.getBean("myBeanFactory");
System.out.println("name:"+bbA.getNameString() + ",age :"+bbA.getAge());
BeanA aTestA = (BeanA) bean.getBean("a");
System.out.println(aTestA);
// 如果希望获取MyFactoryBeanTest的实例,则需要在getBean(beanName)方法时在beanName前显
// 示的加上“&”前缀,例如 bean.getBean("&myBeanFactory");
// 在name 前加&,则获取的是MyFactoryBeanTest实例
MyFactoryBeanTest myFactoryBeanTest = (MyFactoryBeanTest)
bean.getBean("&myBeanFactory");
System.out.println("MyFactoryBeanTest对象:"+":"+myFactoryBeanTest.getUserInfo());
注意: 如果希望获取MyFactoryBeanTest的实例,则需要在getBean(beanName)方法时在beanName前显
示的加上“&”前缀,例如 bean.getBean("&myBeanFactory");
在AbstractBeanFactory类中。
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
getBean(dependsOnBean);
registerDependentBean(dependsOnBean, beanName);
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
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;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; " +
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type [" +
ClassUtils.getQualifiedName(requiredType) + "]", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
在获取到bean之后,会调用频率最高的方法:getObjectForBeanInstance()。无论是从缓存中获取beanh还是根据不同的scope策略来加载bean,都会调用此方法。其方法j就是用于检测当前bean是否是FactoryBean类型的bean,如果是,那么需要调用该bean对应的FactoryBean实例中的getObject()作为返回值。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// 如果指定的name是工厂相关(以&为前缀)且beanInstance又不是FactoryBean类型则验证不通
//过
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// 现在我们有了bean的实例,这个实例k可能会是正常的bean,或者是FactoryBean
// 如果是FactoryBean我们s使用它创建实例,但是如果用户想要直接获取工厂实例还不是工厂的
//getObeact方法对应的s实例,那么传入的name应该加入前缀"&"
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
//加载fACTORYBean
Object object = null;
if (mbd == null) {
//尝试从缓存中加载bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 到这里已经明确知道beanInstance一定是FactoryBean类型
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// containsBeanDefinition检测beanDefinitionMap中也就是在所有已经加载的类中检测是
//否定义beanName
if (mbd == null && containsBeanDefinition(beanName)) {
//将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition,如果指定
//BeanName是子Bean的话 同时会合并父类的相关属性
mbd = getMergedLocalBeanDefinition(beanName);
}
//是否是用户定义的而不是应用程序本身定义的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
从上面的代码逻辑看,只是些功能的性的判断,没有核心的东西,并且委托给了getObectFromFactoryBean。
上面的代码主要的工作:
- 对FactoryBean正确性的验证
- 对非FactoryBean不做任何处理
- 对bean进行转换
- 将从Factory中解析bean的工作委托给getObjectFromFactoryBean
protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
}
return (object != NULL_OBJECT ? object : null);
}
}
else {
return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
}
}
在这个代码只是做了一件事:j就是返回bean,如果是单例的,那就必须要保证q全局唯一,也因为是单例的,所以不必重复创建,k可以使用缓存来提高性能,也就是已经加载的就要记录下来以便于下次复用。否则就直接获取。
private Object doGetObjectFromFactoryBean(
final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//直接调用getObject获取bean
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
if (object != null && shouldPostProcess) {
try {
//调用ObjectFactory的后处理器
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex);
}
}
return object;
}
这个方法才是真正调用了,factorybean的方法getObject来返回,但是并没有直接返回,而是又做了些后处理的操作。
spring在获取bean的规则中有这么一条:尽可能保证所有bean初始化后都会调用注册的BeanPostProcessor的postProcessAfterInitialization方法进行处理,在实际开发过程中大可以针对此特性来设计自己的业务逻辑。