/*
* Copyright 2008-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.hasor.core.container;
import net.hasor.core.*;
import net.hasor.core.EventListener;
import net.hasor.core.info.AbstractBindInfoProviderAdapter;
import net.hasor.core.info.NotifyData;
import net.hasor.core.provider.InstanceProvider;
import net.hasor.core.scope.SingletonScope;
import net.hasor.core.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 整个Hasor将围绕这个类构建!!
* <br/>它,完成了Bean容器的功能。
* <br/>它,完成了依赖注入的功能。
* <br/>它,完成了Aop的功能。
* <br/>它,支持了{@link Scope}作用域功能。
* <br/>它,支持了{@link AppContext}接口功能。
* <br/>它,是万物之母,一切生命的源泉。
* @version : 2015年11月25日
* @author 赵永春(zyc@hasor.net)
*/
public class BeanContainer extends TemplateBeanBuilder implements ScopManager, Observer {
protected Logger logger = LoggerFactory.getLogger(getClass());
private AtomicBoolean inited = new AtomicBoolean(false);
private List<BindInfo<?>> allBindInfoList = new ArrayList<BindInfo<?>>();
private ConcurrentHashMap<String, List<String>> indexTypeMapping = new ConcurrentHashMap<String, List<String>>();
private ConcurrentHashMap<String, BindInfo<?>> idDataSource = new ConcurrentHashMap<String, BindInfo<?>>();
private ConcurrentHashMap<String, Provider<Scope>> scopeMapping = new ConcurrentHashMap<String, Provider<Scope>>();
//
/*-----------------------------------------------------------------------------------BindInfo*/
/**根据ID查找{@link BindInfo}*/
public <T> BindInfo<T> findBindInfoByID(String infoID) {
return (BindInfo<T>) this.idDataSource.get(infoID);
}
public <T> BindInfo<T> findBindInfoByType(Class<T> bindType) {
Hasor.assertIsNotNull(bindType, "bindType is null.");
return findBindInfo(null, bindType);
}
/**通过一个类型获取所有绑定到该类型的上的对象实例。*/
public <T> BindInfo<T> findBindInfo(final String withName, final Class<T> bindType) {
Hasor.assertIsNotNull(bindType, "bindType is null.");
//
List<BindInfo<T>> typeRegisterList = findBindInfoList(bindType);
if (typeRegisterList != null && !typeRegisterList.isEmpty()) {
for (int i = typeRegisterList.size() - 1; i >= 0; i--) {
BindInfo<T> adapter = typeRegisterList.get(i);
if (adapter == null) {
continue;
}
String bindName = adapter.getBindName();
if (StringUtils.isBlank(bindName) && StringUtils.isBlank(withName)) {
return adapter;
}
if (bindName != null && bindName.equals(withName)) {
return adapter;
}
}
}
return null;
}
/**通过一个类型获取所有绑定到该类型的上的对象实例。*/
public <T> List<BindInfo<T>> findBindInfoList(final Class<T> bindType) {
List<String> idList = this.indexTypeMapping.get(bindType.getName());
if (idList == null || idList.isEmpty()) {
logger.debug("getBindInfoByType , never define this type = {}", bindType);
return Collections.EMPTY_LIST;
}
List<BindInfo<T>> resultList = new ArrayList<BindInfo<T>>();
for (String infoID : idList) {
BindInfo<?> adapter = this.idDataSource.get(infoID);
if (adapter != null) {
resultList.add((BindInfo<T>) adapter);
} else {
logger.debug("findBindInfoList , cannot find {} BindInfo.", infoID);
}
}
return resultList;
}
/**获取所有ID。*/
public Collection<String> getBindInfoIDs() {
return this.idDataSource.keySet();
}
/**
* 获取类型下所有Name
* @param targetClass 类型
* @return 返回声明类型下有效的名称。
*/
public Collection<String> getBindInfoNamesByType(Class<?> targetClass) {
List<? extends BindInfo<?>> bindInfoList = this.findBindInfoList(targetClass);
ArrayList<String> names = new ArrayList<String>(bindInfoList.size());
for (BindInfo<?> info : bindInfoList) {
String bindName = info.getBindName();
if (StringUtils.isBlank(bindName)) {
continue;
}
names.add(bindName);
}
return names;
}
//
/*-------------------------------------------------------------------------------------------*/
//
/**
* 创建{@link AbstractBindInfoProviderAdapter},交给外层用于Bean定义。
* @param bindType 声明的类型。
* @param binderSource
*/
public <T> AbstractBindInfoProviderAdapter<T> createInfoAdapter(Class<T> bindType, Class<?> binderSource) {
if (this.inited.get()) {
throw new java.lang.IllegalStateException("container has been started.");
}
//
AbstractBindInfoProviderAdapter<T> adapter = super.createInfoAdapter(bindType, binderSource);
adapter.addObserver(this);
adapter.setBindID(adapter.getBindID());
return adapter;
}
@Override
protected <T> T createObject(final Class<T> targetType, final BindInfo<T> bindInfo, final AppContext appContext) {
boolean isSingleton = testSingleton(targetType, bindInfo, appContext.getEnvironment().getSettings());
//
if (isSingleton) {
Object key = (bindInfo != null) ? bindInfo : targetType;
Provider<Scope> singleton = Hasor.assertIsNotNull(this.scopeMapping.get(ScopManager.SINGLETON_SCOPE));
return singleton.get().scope(key, new Provider<T>() {
public T get() {
return callSuperCreateObject(targetType, bindInfo, appContext);
}
}).get();
} else {
return callSuperCreateObject(targetType, bindInfo, appContext);
}
}
/** 仅执行依赖注入 */
public <T> T justInject(T object, Class<?> beanType, AppContext appContext) throws Throwable {
return super.doInject(object, null, appContext, beanType);
}
private <T> T callSuperCreateObject(Class<T> targetType, BindInfo<T> bindInfo, AppContext appContext) {
return super.createObject(targetType, bindInfo, appContext);
}
//
/*-------------------------------------------------------------------------------------------*/
//
public boolean isInit() {
return this.inited.get();
}
public void doInitializeCompleted(Environment env) {
if (!this.inited.compareAndSet(false, true)) {
return;/*避免被初始化多次*/
}
this.scopeMapping.put(ScopManager.SINGLETON_SCOPE, new InstanceProvider<Scope>(new SingletonScope()));
for (BindInfo<?> info : this.allBindInfoList) {
if (!(info instanceof AbstractBindInfoProviderAdapter)) {
continue;
}
final AbstractBindInfoProviderAdapter<?> infoAdapter = (AbstractBindInfoProviderAdapter<?>) info;
Method initMethod = findInitMethod(infoAdapter.getBindType(), infoAdapter);
boolean singleton = testSingleton(infoAdapter.getBindType(), info, env.getSettings());
if (initMethod != null && singleton) {
//
Hasor.pushStartListener(env, new EventListener<AppContext>() {
public void onEvent(String event, AppContext eventData) throws Throwable {
eventData.getInstance(infoAdapter);//执行init
}
});
}
}
}
/** 当容器停止运行时,需要做Bean清理工作。*/
public void doShutdownCompleted() {
if (!this.inited.compareAndSet(true, false)) {
return;/*避免被销毁多次*/
}
this.indexTypeMapping.clear();
this.idDataSource.clear();
this.scopeMapping.clear();
}
//
/*-------------------------------------------------------------------------------------------*/
//
@Override
public Provider<Scope> registerScope(String scopeName, Provider<Scope> scope) {
Provider<Scope> oldScope = this.scopeMapping.putIfAbsent(scopeName, scope);
if (oldScope == null) {
oldScope = scope;
}
return oldScope;
}
@Override
public Provider<Scope> findScope(String scopeName) {
return this.scopeMapping.get(scopeName);
}
//
/*-------------------------------------------------------------------------------------------*/
//
@Override
public synchronized void update(Observable o, Object arg) {
if (arg == null || !(arg instanceof NotifyData)) {
return;
}
if (o == null || !(o instanceof AbstractBindInfoProviderAdapter)) {
return;
}
//
AbstractBindInfoProviderAdapter target = (AbstractBindInfoProviderAdapter) o;
String bindTypeStr = target.getBindType().getName();
String bindID = target.getBindID();
//
// .新数据初始化
boolean hasOld = this.idDataSource.containsKey(bindID);
if (!hasOld) {
this.allBindInfoList.add(target);
this.idDataSource.put(bindID, target);
List<String> newTypeList = new ArrayList<String>();
List<String> typeList = indexTypeMapping.putIfAbsent(bindTypeStr, newTypeList);
if (typeList == null) {
typeList = newTypeList;
}
typeList.add(bindID);
}
// .
NotifyData notifyData = (NotifyData) arg;
Object oldValue = notifyData.getOldValue();
Object newValue = notifyData.getNewValue();
if ((newValue == null && oldValue == null) || (newValue != null && newValue.equals(oldValue))) {
return;/*没有变化*/
}
// .
if ("bindID".equalsIgnoreCase(notifyData.getKey())) {
newValue = Hasor.assertIsNotNull(newValue);
if (this.idDataSource.containsKey(newValue)) {
throw new IllegalStateException("duplicate bind -> id value is " + newValue);
}
this.idDataSource.put((String) newValue, target);
this.idDataSource.remove(oldValue);
List<String> idList = this.indexTypeMapping.get(target.getBindType().getName());
if (idList == null) {
throw new IllegalStateException("beans were not registered correctly.");
}
idList.remove(oldValue);
idList.add((String) newValue);
}
// .
if ("bindName".equalsIgnoreCase(notifyData.getKey())) {
newValue = Hasor.assertIsNotNull(newValue);
BindInfo bindInfo = this.findBindInfo((String) newValue, target.getBindType());
if (bindInfo != null) {
throw new IllegalStateException("duplicate bind -> bindName '" + newValue + "' conflict with '" + bindInfo + "'");
}
}
// .
if ("bindType".equalsIgnoreCase(notifyData.getKey())) {
throw new IllegalStateException("'bindType' are not allowed to be changed");
}
}
}