Struts2学习笔记之--容器

   引入容器是以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)
   
   ...此处省略很多代码
}

  通过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);
	}
	}
}

通过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);
	}	
	
}

 对一个对象的注入是通过调用注入器(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);
			}
		}
	}



}

 原来依赖注入是通过java中最基本的反射机制,把field注入进去了,注入的内容是通过工厂来拿的。


看了半天源码和书(Struts2技术内幕),对于Container有几点总结和归纳

  1. 容器是一个辅助的编程元素,它一定要是一个全局的、统一的编程元素

  2. 对象的生命周期管理有两个方面1.程序运行期对象的创建  2.对象和其依赖的处理

  3. struts容器管理的对象是在struts/xwork配置中声明的对象

  4. objectFactory这个也没有提到。因为container中有getInstance和inject两个方法,可我们实际上想要在拿到一个容器托管对象的同时,希望它已经被注入好了。这是objectFactory就提供了一个比较方便的方法,直接给我们一个完美的实例。


第一次写博客,分析代码也前言不搭后语,以后慢慢锻炼吧~~








转载于:https://my.oschina.net/u/1165712/blog/311273

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值