對象的生命週期管理2大核心問題: java
1.在程序的運行期,對象實例的建立和引用 apache
2.對象與其關聯對象的依賴關係的處理機制 編程
每一個對象自身對於邏輯的執行能力,被其所依賴的對象反向控制了,這也就是控制反轉的本質含義。 緩存
應該引入一個與具體的業務邏輯徹底無關的額外的編程元素容器來幫助進行對象的生命週期管理。 數據結構
xwork框架中的容器被定義成爲一個java接口,源碼: 多線程
package com.opensymphony.xwork2.inject; import java.io.Serializable; import java.util.Set; public interface Container extends Serializable { /** * Default dependency name. * 定義默認的對象標示 */ String DEFAULT_NAME = "default"; /** * Injects dependencies into the fields and methods of an existing object. * 進行對象依賴注入的基本接口,做爲參數的object將被xwork容器進行處理。 * object內部生命有@inject的字段和方法,都將被注入受到容器託管的對象 * 從而創建起依賴關係 */ void inject(Object o); /** * Creates and injects a new instance of type {@code implementation}. * 建立一個類的實例並進行對象依賴注入 */ <T> T inject(Class<T> implementation); /** * Gets an instance of the given dependency which was declared in * {@link com.opensymphony.xwork2.inject.ContainerBuilder}. */ <T> T getInstance(Class<T> type, String name); /** * Convenience method. Equivalent to {@code getInstance(type, * DEFAULT_NAME)}. */ <T> T getInstance(Class<T> type); /** * Gets a set of all registered names for the given type * @param type The instance type * @return A set of registered names */ Set<String> getInstanceNames(Class<?> type); /** * Sets the scope strategy for the current thread. * 設置當前線程的做用範圍的策略 */ void setScopeStrategy(Scope.Strategy scopeStrategy); /** * Removes the scope strategy for the current thread. */ void removeScopeStrategy(); }容器是一個輔助的編程元素,他在整個系統中應該被實例化爲一個全局的、單例的對象
獲取對象實例: app
容器的getInstance方法來獲取對象的實例時,咱們只能獲取那些「被容器接管」的對象實例。被接管的對象有: 框架
(1)在bean節點中聲明的框架內部對象 ide
(2)在bean節點中聲明的自定義的對象 函數
(3)在contant節點和properties文件中聲明的系統運行參數
對象的依賴注入:
當調用容容器的inject方法來實施依賴注入操做時,所操做的對象卻不單單僅限於「容器配置元素」中所定義的對象。由於咱們隊inject方法的定義是,只要傳入一個對象的實例,容器將負責創建起傳入對象實例與容器託管對象之間的依賴關係。
xwork容器被定義成一個接口,期內部封裝了一組操做方法。既然並非一個具體的數據結構類,那麼容器究竟是怎麼保存數據的呢?xwork容器的實現類ContainerImpl的源碼。
class ContainerImpl implements Container { final Map<Key<?>, InternalFactory<?>> factories; final Map<Class<?>,Set<String>> factoryNamesByType; ContainerImpl(Map<Key<?>, InternalFactory<?>> factories) { this.factories = factories; Map<Class<?>,Set<String>> map = new HashMap<Class<?>,Set<String>>(); for (Key<?> key : factories.keySet()) { Set<String> names = map.get(key.getType()); if (names == null) { names = new HashSet<String>(); map.put(key.getType(), names); } names.add(key.getName()); } for (Entry<Class<?>,Set<String>> entry : map.entrySet()) { entry.setValue(Collections.unmodifiableSet(entry.getValue())); } this.factoryNamesByType = Collections.unmodifiableMap(map); }factories是由構造函數傳遞進入並緩存與內部,而factoryNameByType則在factories的基礎上作了一個根據名稱進行尋址的緩存映射關係。
factories這個存儲結構中的Key,定義:
package com.opensymphony.xwork2.inject; /** * Dependency mapping key. Uniquely identified by the required type and name. * * @author crazybob@google.com (Bob Lee) */ class Key<T> { final Class<T> type; final String name; final int hashCode; private Key(Class<T> type, String name) { if (type == null) { throw new NullPointerException("Type is null."); } if (name == null) { throw new NullPointerException("Name is null."); } this.type = type; this.name = name; hashCode = type.hashCode() * 31 + name.hashCode(); } Class<T> getType() { return type; } String getName() { return name; } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object o) { if (!(o instanceof Key)) { return false; } if (o == this) { return true; } Key other = (Key) o; return name.equals(other.name) && type.equals(other.type); } @Override public String toString() { return "[type=" + type.getName() + ", name='" + name + "']"; } static <T> Key<T> newInstance(Class<T> type, String name) { return new Key<T>(type, name); } }Key其實是由一個二元組構成的對象集合。而這個二元組構成對象的type和name實際上正好能夠和bean及誒單的定義對應起來,struts-default.xml部分代碼:
<bean class="com.opensymphony.xwork2.ObjectFactory" name="xwork" /> <bean type="com.opensymphony.xwork2.ObjectFactory" name="struts" class="org.apache.struts2.impl.StrutsObjectFactory" />factories結構中的value,InternalFactory
interface InternalFactory<T> extends Serializable { /** * Creates an object to be injected. * * @param context of this injection * @return instance to be injected */ T create(InternalContext context); }這個泛型接口只有一個create方法。含義:一旦實現這個接口,咱們就須要指定對象的建立機制。
重點:在容器內部進行緩存的是對象實例的構建方法,而不是實力自己。這就讓容器看起來像一個工廠的集合,可以根據不一樣的要求,製造出不一樣種類的對象實例。
注入器:
除了獲取對象實例,xwork容器的另外一個重要的操做接口是實施對象的依賴注入。xwork容器的內部緩存一個對象製造工廠factories用於在運行期可以建立對象實例並返回以外,還須要另外一類緩存的幫助,用於記錄對象魚對象之間的依賴關係。這一類緩存數據在xwork容器的額內部被稱之爲注入器,相關代碼:
/** * Field and method injectors. */ final Map<Class<?>, List<Injector>> injectors = new ReferenceCache<Class<?>, List<Injector>>() { @Override protected List<Injector> create(Class<?> key) { List<Injector> injectors = new ArrayList<Injector>(); addInjectors(key, injectors); return injectors; } };referenceCache是xwork礦建中對於緩存的一種簡單實現,在運行期構建Map內容的機制。
public abstract class ReferenceCache<K, V> extends ReferenceMap<K, V> { private static final long serialVersionUID = 0; transient ConcurrentMap<Object, Future<V>> futures = new ConcurrentHashMap<Object, Future<V>>(); transient ThreadLocal<Future<V>> localFuture = new ThreadLocal<Future<V>>(); public ReferenceCache(ReferenceType keyReferenceType, ReferenceType valueReferenceType) { super(keyReferenceType, valueReferenceType); } protected abstract V create(K key); }應用ThreadLocal模式規避了對象操做的多線程問題
當調用map中的接口get時,referenceCache首先查找器內部是否存在相應的緩存對象,若是存在直接返回;若是不存在,則調用其抽象方法create根據key的內容產生對象並緩存起來。
注入器就是xwork容器中實施依賴注入的核心。注入器自己是一個接口,規定了對象進行依賴注入的行爲:
interface Injector extends Serializable { void inject(InternalContext context, Object o); }在注入器的referenceCache定義中,全部的注入器都是在運行期動態添加的,其核心方法create會調用addInjectors掃描全部知足條件的注入器,而且添加到referenceCache中
/** * Field and method injectors. */ final Map<Class<?>, List<Injector>> injectors = new ReferenceCache<Class<?>, List<Injector>>() { @Override protected List<Injector> create(Class<?> key) { List<Injector> injectors = new ArrayList<Injector>(); addInjectors(key, injectors); return injectors; } }; /** * Recursively adds injectors for fields and methods from the given class to * the given list. Injects parent classes before sub classes. */ void addInjectors(Class clazz, List<Injector> injectors) { if (clazz == Object.class) { return; } // Add injectors for superclass first. addInjectors(clazz.getSuperclass(), injectors); // TODO (crazybob): Filter out overridden members. addInjectorsForFields(clazz.getDeclaredFields(), false, injectors); addInjectorsForMethods(clazz.getDeclaredMethods(), false, injectors); }
void addInjectorsForFields(Field[] fields, boolean statics, List<Injector> injectors) { addInjectorsForMembers(Arrays.asList(fields), statics, injectors, new InjectorFactory<Field>() { public Injector create(ContainerImpl container, Field field, String name) throws MissingDependencyException { return new FieldInjector(container, field, name); } }); }
inject的基本實現,它是基於Field和method這兩個最基本的對象元素實現的,其源碼:
static class FieldInjector implements Injector { final Field field; final InternalFactory<?> factory; final ExternalContext<?> externalContext; public FieldInjector(ContainerImpl container, Field field, String name) throws MissingDependencyException { this.field = field; if (!field.isAccessible()) { SecurityManager sm = System.getSecurityManager(); try { if (sm != null) sm.checkPermission(new ReflectPermission("suppressAccessChecks")); field.setAccessible(true); } catch(AccessControlException e) { throw new DependencyException("Security manager in use, could not access field: " + field.getDeclaringClass().getName() + "(" + field.getName() + ")", e); } } Key<?> key = Key.newInstance(field.getType(), name); factory = container.getFactory(key); if (factory == null) { throw new MissingDependencyException( "No mapping found for dependency " + key + " in " + field + "."); } this.externalContext = ExternalContext.newInstance(field, key, container); } public void inject(InternalContext context, Object o) { ExternalContext<?> previous = context.getExternalContext(); context.setExternalContext(externalContext); try { field.set(o, factory.create(context)); } catch (IllegalAccessException e) { throw new AssertionError(e); } finally { context.setExternalContext(previous); } } }
在Field的構造函數中,在容器內部根據type和name進行對象構造工廠factory的尋址。以後的inject調用過程,只不過是調用factory構建對象,並使用java中最爲普通的反射機制來完成對象的依賴注入。
對象的建立和對象的依賴注入是對象生命週期管理的2個不一樣的方面,於是他們在container接口中所表現出來的具體方法也不一樣。
既然對象管理的這兩個方面之間的聯繫如此緊密,那麼在xwork中有沒有一個統一的操做接口將這兩個操做封裝在一塊兒?xwork中提供了這樣一個工具類objectFactory,容許程序猿在程序的運行期動態的構建一個新的對象,而且爲這個新構建的對象實施依賴注入操做,相關源碼:
public class ObjectFactory implements Serializable { private static final Logger LOG = LoggerFactory.getLogger(ObjectFactory.class); private transient ClassLoader ccl; private Container container; protected ReflectionProvider reflectionProvider; @Inject(value="objectFactory.classloader", required=false) public void setClassLoader(ClassLoader cl) { this.ccl = cl; } @Inject public void setReflectionProvider(ReflectionProvider prov) { this.reflectionProvider = prov; } @Inject public void setContainer(Container container) { this.container = container; } public Object buildAction(String actionName, String namespace, ActionConfig config, Map<String, Object> extraContext) throws Exception { return buildBean(config.getClassName(), extraContext); } /** * Build a generic Java object of the given type. * * @param clazz the type of Object to build * @param extraContext a Map of extra context which uses the same keys as the {@link com.opensymphony.xwork2.ActionContext} */ public Object buildBean(Class clazz, Map<String, Object> extraContext) throws Exception { return clazz.newInstance(); } /** * @param obj */ protected Object injectInternalBeans(Object obj) { if (obj != null && container != null) { container.inject(obj); } return obj; } public Object buildBean(String className, Map<String, Object> extraContext, boolean injectInternal) throws Exception { Class clazz = getClassInstance(className); Object obj = buildBean(clazz, extraContext); if (injectInternal) { injectInternalBeans(obj); } return obj; } 。。。。。。。。 }
objectFactory用於構建xwork礦建內部對象action、interceptor、result、validator的快捷方法;objectFactory用於構建一個普通bean的核心方法buildBean,包含了對象建立和依賴注入這兩個核心過程,於是成爲一個統一的對象初始化操做接口。
上面內容參考《struts2技術內幕》