引入容器是以Java为代表的面向对象的编程语言发展过程中的一个里程碑,所以几乎所有的开源框架都有自己的容器实现。有的甚至以容器为核心做为其基础构建(比如spring)。
做为一个互联网企业的程序员,有空看了下Struts2的源码级实现,啥也不说,先上代码
public interface Container{
/***
*将Object内声明有@inject的字段和方法,都将被注入受到容器托管的对象
*/
void inject(Object o);
/***
*获取一个类的实例,并进行依赖注入
*/
<T> T inject(Class<T> type,String name);
/***
*根据type,获取容器中的实例
*/
<T> getInstance(Class<T> type)
/***
*根据type和name,获取容器中的实例
*/
<T> getInstance(Class<T> type,String name)
...此处省略很多代码
}
public interface Container{
/***
*将Object内声明有@inject的字段和方法,都将被注入受到容器托管的对象
*/
void inject(Object o);
/***
*获取一个类的实例,并进行依赖注入
*/
<T> T inject(Class<T> type,String name);
/***
*根据type,获取容器中的实例
*/
<T> getInstance(Class<T> type)
/***
*根据type和name,获取容器中的实例
*/
<T> getInstance(Class<T> type,String name)
...此处省略很多代码
}
通过Container的定义可以看出,Container是个接口,主要的几个功能就是获取 1.获取对象 2.对象的依赖注入。这也就是容器最基本也是最重要的两个功能。
我们简单看一个Container的实现ContainerImpl,先看一下容器获取对象的方法:
class ContainerImpl implements Container {
final Map<Key<?>, InternalFactory<?>> factories;
final Map<Class<?>, Set<String>> factoryNamesByType;
/***
*getInstance的最重要的实现,其他的两个重载函数都是调用这个的
*/
<T> T getInstance( Class<T> type, String name, InternalContext context ) {
ExternalContext<?> previous = context.getExternalContext();
//key是一个二元组,保存class和name
Key<T> key = Key.newInstance(type, name);
context.setExternalContext(ExternalContext.newInstance(null, key, this));
try {
InternalFactory o = getFactory(key);
if (o != null) {
//InternalFactory是个接口,工厂们都是实现create方法,提供一套创建对象的机制
return getFactory(key).create(context);
} else {
return null;
}
} finally {
context.setExternalContext(previous);
}
}
}
class ContainerImpl implements Container {
final Map<Key<?>, InternalFactory<?>> factories;
final Map<Class<?>, Set<String>> factoryNamesByType;
/***
*getInstance的最重要的实现,其他的两个重载函数都是调用这个的
*/
<T> T getInstance( Class<T> type, String name, InternalContext context ) {
ExternalContext<?> previous = context.getExternalContext();
//key是一个二元组,保存class和name
Key<T> key = Key.newInstance(type, name);
context.setExternalContext(ExternalContext.newInstance(null, key, this));
try {
InternalFactory o = getFactory(key);
if (o != null) {
//InternalFactory是个接口,工厂们都是实现create方法,提供一套创建对象的机制
return getFactory(key).create(context);
} else {
return null;
}
} finally {
context.setExternalContext(previous);
}
}
}
通过ContainerImpl的filed,缓存了一个factories,Key是个二元组,存放了class和name,InternalFactory存放的就是对应的工厂。原来容器的内部就是一个工厂!容器的getInstance方法其实就是从工厂中生产出来我们需要的实例来
Container中比较精彩的部分应该就是依赖注入了:
class ContainerImpl implements Container {
/***
*依赖注入的核心方法
*/
void inject( Object o, InternalContext context ) {
//根据被注入的对象,生成一系列的注入器,并调用其inject方法
List<Injector> injectors = this.injectors.get(o.getClass());
for ( Injector injector : injectors ) {
injector.inject(context, o);
}
}
/**
*生成注入器
**/
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);
}
}
class ContainerImpl implements Container {
/***
*依赖注入的核心方法
*/
void inject( Object o, InternalContext context ) {
//根据被注入的对象,生成一系列的注入器,并调用其inject方法
List<Injector> injectors = this.injectors.get(o.getClass());
for ( Injector injector : injectors ) {
injector.inject(context, o);
}
}
/**
*生成注入器
**/
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);
}
}
对一个对象的注入是通过调用注入器(Injector的inject方法实现的),在生成injector的方法中可以看出,它会递归的调用superclass的addInjectors方法。并对field和method分别进行注入。我们挑fieldInjector来看看它到底做了什么
class ContainerImpl implements Container {
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);
}
}
}
}
class ContainerImpl implements Container {
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);
}
}
}
}
原来依赖注入是通过java中最基本的反射机制,把field注入进去了,注入的内容是通过工厂来拿的。
看了半天源码和书(Struts2技术内幕),对于Container有几点总结和归纳
- 容器是一个辅助的编程元素,它一定要是一个全局的、统一的编程元素
- 对象的生命周期管理有两个方面1.程序运行期对象的创建 2.对象和其依赖的处理
- struts容器管理的对象是在struts/xwork配置中声明的对象
- objectFactory这个也没有提到。因为container中有getInstance和inject两个方法,可我们实际上想要在拿到一个容器托管对象的同时,希望它已经被注入好了。这是objectFactory就提供了一个比较方便的方法,直接给我们一个完美的实例。