FactoryBean是spring框架定義的一個接口. 用于自定義bean的整個實例化過程;
說到實例化,默認(rèn)spring bean只有給beanFactory注冊beanDefinition就可以自動完成實例化, 這種方式能滿足絕大多數(shù)的實例化需求. FactoryBean是為了滿足復(fù)雜實例化的需求,比如aop生成代理對象, 自定義接口給接口生成代理對象等卫袒。
用法.
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
// 定義beanDefinition
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(UserComponentFactoryBean.class);
// 自動注入
builder.setAutowireMode(2);
annotationConfigApplicationContext.registerBeanDefinition("userComponentFactoryBean", builder.getBeanDefinition());
annotationConfigApplicationContext.refresh();
public class UserComponentFactoryBean implements FactoryBean<UserComponent> {
private UserComponent userComponent;
@Override
public UserComponent getObject() throws Exception {
if (userComponent == null) {
userComponent = new UserComponent();
System.out.println("------------ factoryBean----" + userComponent.hashCode());
}
return userComponent;
}
@Override
public Class<?> getObjectType() {
return UserComponent.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
這里使用注冊beanDefinition的方式讓beanFactory感知到有FactoryBean该贾,當(dāng)然也可以用包掃描的方式加@Component诉稍。
這里UserComponentFactoryBean的getObject()方法獲取對象實例只是示范赶熟,并不規(guī)范茫负。
注意:如果UserCompontFactoryBean有依賴其他bean破停,F(xiàn)actoryBean不會自動完成注入翅楼。
如果需要獲取bean關(guān)聯(lián)的FactoryBean需要在beanName前加上 &
ProxyFactoryBean
spring中使用ProxyFactoryBean創(chuàng)建代理。
ProxyFactoryBean可以配置的屬性有.
- proxyTargetClass: 如果要對類進(jìn)行代理真慢,這個屬性設(shè)置為true
- optimize: 針對CGLIB優(yōu)化.
- frozen: 凍結(jié)配置毅臊。如果為true有倆個作用,一個是不允許CGLIB優(yōu)化黑界, 另一個是代理創(chuàng)建后不允許手動進(jìn)行增強的添加修改管嬉。默認(rèn)是false, 所以一般情況下可以進(jìn)行增強的手動添加修改;
- exposeProxy:是否暴露代理對象皂林。如果是true, 則在增強點/目標(biāo)對象可以通過AopContext.currentProxy()拿到代理對象;
- proxyInterfaces: string對象數(shù)組, 用于指定代理對象實現(xiàn)的接口。如果有值且-proxyTargetClass=false將啟用jdk代理.
- interceptoreNames: 數(shù)組, 聲明增強點集合蚯撩〈”叮可以用* 一次匹配多個增強點;
- singleton: ProxyFactoryBean的getObject方法是否返回單例;
示例
- 定義被代理對象
public class TargetBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object getProxy() {
// 在被代理對象里獲取 代理
return AopContext.currentProxy();
}
@Override
public String toString() {
return "TargetBean{" +
"name='" + name + '\'' +
'}';
}
}
- 定義ProxyFactoryBean, 并設(shè)置一個增強點
@Configuration
public class FactoryBeanConfig {
@Bean("debugInterceptor")
public DebugInterceptor getInterceptor() {
return new DebugInterceptor();
}
@Bean
public ProxyFactoryBean getProxyFactoryBean() {
ProxyFactoryBean pfb = new ProxyFactoryBean();
pfb.setInterceptorNames("debugInterceptor");
pfb.setTarget(new TargetBean());
// 暴露代理對象
pfb.setExposeProxy(true);
return pfb;
}
}
- 啟動
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.scan("com.xie.java.aop.factorybean");
applicationContext.refresh();
TargetBean targetBean = applicationContext.getBean(TargetBean.class);
System.out.println("target bean :" + targetBean);
System.out.println("proxy bean :" + targetBean.getProxy());
// 任何代理對象都可以強制轉(zhuǎn)換成 Advised對象
Advised advised = (Advised) targetBean;
System.out.println("advised :" + advised);
for (Advisor ad : advised.getAdvisors()) {
System.out.println("ad :" + ad );
System.out.println(" count = " + ((DebugInterceptor) ad.getAdvice()).getCount());
// 如果frozen = false, 可動態(tài)添加修改增強點
}
以上示例可以看出, ProxyFactoryBean是spring bean對象胎挎,目標(biāo)類TargetBean不能是spring bean, 不然 getBean(TargetBean.class)會報異常沟启。
getBean(TargetBean.class)查找ProxyFactoryBean的流程如下
1、根據(jù)類型TargetBean.class 查詢spring容器中的所有bean Definition; 如果是FactoryBean則觸發(fā)getType方法犹菇。
代碼來自 DefaultListableBeanFactory
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<String>();
// Check all bean definitions.
for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name
// is not defined as alias for some other bean.
if (!isAlias(beanName)) {
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
if (!mbd.isAbstract() && (allowEagerInit ||
(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
// In case of FactoryBean, match object created by FactoryBean.
// 判斷bean Definition是否是FactoryBean類型
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
boolean matchFound =
(allowEagerInit || !isFactoryBean ||
(dbd != null && !mbd.isLazyInit()) || containsSingleton(beanName)) &&
(includeNonSingletons ||
(dbd != null ? mbd.isSingleton() : isSingleton(beanName))) &&
isTypeMatch(beanName, type);
if (!matchFound && isFactoryBean) {
// In case of FactoryBean, try to match FactoryBean instance itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type);
}
if (matchFound) {
result.add(beanName);
}
}
}
..... 此處省略
// Check manually registered singletons too.
// 檢查手動注冊的單例
for (String beanName : this.manualSingletonNames) {
try {
// In case of FactoryBean, match object created by FactoryBean.
// 又一個FactoryBean判斷
if (isFactoryBean(beanName)) {
if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
result.add(beanName);
// Match found for this bean: do not match FactoryBean itself anymore.
continue;
}
// In case of FactoryBean, try to match FactoryBean itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
}
// Match raw bean instance (might be raw FactoryBean).
if (isTypeMatch(beanName, type)) {
result.add(beanName);
}
}
... 此處省略
}
return StringUtils.toStringArray(result);
}
2德迹、 找到ProxyFactoryBean后, 根據(jù)ProxyFactoryBean的 bean name 觸發(fā)getBean(name, type args)
找到ProxyFactoryBean的實例后 觸發(fā)getObjectForBeanInstance方法,從bean里獲取bean
代碼來著 AbstractBeanFactory
/**
* Get the object for the given bean instance, either the bean
* instance itself or its created object in case of a FactoryBean.
* @param beanInstance the shared bean instance
* @param name name that may include factory dereference prefix
* @param beanName the canonical bean name
* @param mbd the merged bean definition
* @return the object to expose for the bean
*/
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
// 此處 觸發(fā)從FactoryBean 緩存 獲取 對象
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 觸發(fā)直接從FactoryBean 獲取對象
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
3揭芍、觸發(fā)ProxyFactory的 getObject()方法
public Object getObject() throws BeansException {
initializeAdvisorChain();
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
總結(jié)ProxyFactoryBean到目標(biāo)代理對象的流程胳搞。
1、spring根據(jù)getBean的目標(biāo)類型查找BeanDefinition
2称杨、如果BeanDefinition是FactoryBean肌毅,則觸發(fā)其getType方法
3、拿到ProxyFactoryBean bean后列另, 最終觸發(fā)FactoryBean的getObject方法拿到代理對象.
MyBatise在FactoryBean上的應(yīng)用
MapperFactoryBean<T>
程序急需要定義Mapper接口芽腾,MapperFactoryBean就會為其生成代理對象.
Dubbo在FactoryBean上的應(yīng)用
ReferenceBean<T>
dubbo會為標(biāo)識為@Reference的注入使用javassist生成具體的bean.
Spring Context在FactoryBean上的應(yīng)用
ScopedProxyFactoryBean
給聲明了@RefreshScope的類生成代理, 處理配置實時刷新同步的問題