Struts2框架及其设计模式
Struts2容器 容器是框架的核心,可以利用容器生成bean,也可以完成依赖注入等,这些都是容器的基本功能,Struts2容器与之前介绍的Spring容器、Springmvc容器是大不一样的。Spring典型容器是ClassPathXmlApplicationContext,Springmvc延续Spring的风格,其典型容器是XmlWebApplicationContext
Struts2容器
容器是框架的核心,可以利用容器生成bean,也可以完成依赖注入等,这些都是容器的基本功能,Struts2容器与之前介绍的Spring容器、Springmvc容器是大不一样的。Spring典型容器是ClassPathXmlApplicationContext,Springmvc延续Spring的风格,其典型容器是XmlWebApplicationContext,它们都是AbstractRefreshableApplicationContext的子类,以下为AbstractRefreshableApplicationContext、DefaultListableBeanFactory部分源码:
// AbstractRefreshableApplicationContext.java部分源码
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
private Boolean allowBeanDefinitionOverriding;
private Boolean allowCircularReferences;
// 包含DefaultListableBeanFactory
private DefaultListableBeanFactory beanFactory;
/** Synchronization monitor for the internal BeanFactory */
private final Object beanFactoryMonitor = new Object();
// DefaultListableBeanFactory部分源码
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
/** Map from serialized id to factory instance */
private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
new ConcurrentHashMap<String, Reference<DefaultListableBeanFactory>>(8);
/** Optional id for this factory, for serialization purposes */
private String serializationId;
/** Whether to allow re-registration of a different definition with the same name */
private boolean allowBeanDefinitionOverriding = true;
/** Whether to allow eager class loading even for lazy-init beans */
private boolean allowEagerClassLoading = true;
/** Resolver to use for checking if a bean definition is an autowire candidate */
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
/** Map from dependency type to corresponding autowired value */
private final Map<Class<?>, Object> resolvableDependencies = new HashMap<Class<?>, Object>(16);
/** Map of bean definition objects, keyed by bean name */
// BeanDefinition键值对
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
/** Map of singleton and non-singleton bean names keyed by dependency type */
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);
/** Map of singleton-only bean names keyed by dependency type */
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);
/** List of bean definition names, in registration order */
private final List<String> beanDefinitionNames = new ArrayList<String>();
/** Whether bean definition metadata may be cached for all beans */
private boolean configurationFrozen = false;
/** Cached array of bean definition names in case of frozen configuration */
private String[] frozenBeanDefinitionNames;
在Spring中,以Map<String, BeanDefinition> beanDefinitionMap形式缓存xml等配置解析后的BeanDefinition,且DefaultListableBeanFactory(AbstractBeanFactory)提供多种形式的getBean,以获取bean。
在Struts2中,其容器为ContainerImpl:
// ContainerImpl.java部分源码
class ContainerImpl implements Container {
// 其体现在InternalFactory的键值对,缓存的都是InternalFactory
// 直接利用InternalFactory创建bean
final Map<Key<?>, InternalFactory<?>> factories;
final Map<Class<?>, Set<String>> factoryNamesByType;
// InternalFactory.java
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);
}
Struts2框架中的设计模式
ThreadLocal设计模式
ContainerHolder的ThreadLocal设计模式实现:
/** ContainerHolder.java */
// ContainerHolder为典型的ThreadLocal设计模式实现
class ContainerHolder {
private static ThreadLocal<Container> instance = new ThreadLocal<Container>();
public static void store(Container instance) {
ContainerHolder.instance.set(instance);
}
public static Container get() {
return ContainerHolder.instance.get();
}
public static void clear() {
ContainerHolder.instance.remove();
}
}
ThreadLocal设计模式本质:
/** ThreadLocal.java */
public void set(T value) {
// 获取当前线程
Thread t = Thread.currentThread();
// 获取当前线程的threadLocals属性
ThreadLocalMap map = getMap(t);
if (map != null)
// 设置ThreadLocal—instance键值对
map.set(this, value);
else
// 创建ThreadLocalMap,且设置ThreadLocal对应的初始值
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
/** Thread.java */
// Thread部分源码
public class Thread implements Runnable {
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
...
}
/** ThreadLocalMap.java */
private void set(ThreadLocal key, Object value) {
// We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
/** ThreadLocal.java */
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocal设计模式针对thread是线程安全的,在Thread中有ThreadLocal.ThreadLocalMap threadLocals属性,其key-value对应为ThreadLocal—实际存储对象,所以在多线程并发情况下,每一个线程存储的是对象的副本,线程之间隔离,这样当前线程对副本的操作不存在竞争关系,从这个层面体现为线程安全的。ThreadLocal设计模式在Struts2体现的淋漓尽致。
内部类工厂设计模式
以ContainerBuilder中添加InternalFactory为例说明:
/** ContainerBuilder.java */
public <T> ContainerBuilder factory(Class<T> type,
Class<? extends T> implementation, Scope scope) {
return factory(type, Container.DEFAULT_NAME, implementation, scope);
}
public <T> ContainerBuilder factory(final Class<T> type, final String name,
final Class<? extends T> implementation, final Scope scope) {
// This factory creates new instances of the given implementation.
// We have to lazy load the constructor because the Container
// hasn't been created yet.
InternalFactory<? extends T> factory = new InternalFactory<T>() {
volatile ContainerImpl.ConstructorInjector<? extends T> constructor;
@SuppressWarnings("unchecked")
public T create(InternalContext context) {
if (constructor == null) {
this.constructor =
context.getContainerImpl().getConstructor(implementation);
}
return (T) constructor.construct(context, type);
}
@Override
public String toString() {
return new LinkedHashMap<String, Object>() {{
put("type", type);
put("name", name);
put("implementation", implementation);
put("scope", scope);
}}.toString();
}
};
return factory(Key.newInstance(type, name), factory, scope);
}
private <T> ContainerBuilder factory(final Key<T> key,
InternalFactory<? extends T> factory, Scope scope) {
ensureNotCreated();
checkKey(key);
final InternalFactory<? extends T> scopedFactory =
scope.scopeFactory(key.getType(), key.getName(), factory);
factories.put(key, scopedFactory);
if (scope == Scope.SINGLETON) {
singletonFactories.add(new InternalFactory<T>() {
public T create(InternalContext context) {
try {
context.setExternalContext(ExternalContext.newInstance(
null, key, context.getContainerImpl()));
return scopedFactory.create(context);
} finally {
context.setExternalContext(null);
}
}
});
}
return this;
}
更多推荐
所有评论(0)