练习-模拟依赖注入的代码

下午花了点没事做的时间做了一个利用反射进行依赖注入的范例,通过这个代码可以大概知道ejb容器和其他javaee容器是怎样进行依赖注入的。

可以自己做一个di模块,放在自己的desktop程序里进行注入。这样就不需要依靠容器也能IOC啦~


package cn.edu.zsu.snippet.inject;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.logging.Logger;

import javax.inject.Inject;

import cn.edu.zsu.snippet.annotation.Run;

/**
 * 模拟依赖注入
 * 
 * @author lijinting
 * 
 */
public class DependencyInjection {

	private final Logger logger = Logger.getLogger(getClass().getName());

	/**
	 * 获取宿主的类型,把宿主类型声明为域便于修改和复用。
	 */
	private final Class<?> hostType = Host.class;

	/**
	 * {@literal 试下这种注释方法 ^-^ 忽略这段继续看下文。} {@code @Run} 标注的方法,表示这个方法是一个执行入口。
	 * {@code cn.edu.zsu.snippet.inject.DependencyInjection } 是一个Command 模式里面的
	 * Concret Command。 将会被相应的Command Receiver调用。Receiver根据Annotation
	 * {@code @Run} 找到相应的 方法,然后予以执行。
	 */
	@Run
	public void main() {

		logger.info(String.format("checkin' in an instance of %s", getClass()
				.getName()));

		try {

			Host host = (Host) hostType.newInstance();

			Field[] fields = hostType.getDeclaredFields();
			for (Field field : fields) {
				// 如果当前的Field有@Inject注解,就把当前field的类型get出来
				//
				Annotation[] annos = field.getDeclaredAnnotations();
				for (Annotation anno : annos) {
					if (anno.annotationType() == Inject.class) {
						logger.info(String.format(
								"找到当前Field : %s %s 被@Inject注解了。", field
										.getType().getName(), field.getName()));
						Class<?> fieldType = field.getType();

						logger.info("获得field类型的一个实例");
						Object value = fieldType.newInstance();

						inject(field, host, value, true);
					}
				}
			}

			host.checkMember();
		} catch (InstantiationException | IllegalAccessException e) {
			if (e.getMessage() != null) {
				logger.severe(e.getMessage());
				e.printStackTrace();
			}
		} finally {
		}
	}

	/**
	 * <pre>
	 * 抄了{@link org.apache.commons.lang.reflect.FieldUtils}里面的代码。
	 * 实际上就是把FieldUtils的方法
	 * <code> public static void writeField(Field field, Object target, Object value, boolean forceAccess) throws IllegalAccessException </code>
	 * 和它所引用的两个变量和方法:
	 * <code>
	 * class FieldUtils{
	 * // ...
	 * private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
	 * // ...
	 * }</code> 
	 * <code>MemberUtils.setAccessibleWorkaround(Field field)</code>
	 * extract到方法体里面。方便查看。
	 * </pre>
	 * 
	 * @param field
	 *            to write
	 * @param target
	 *            the object to call on, may be null for static fields
	 * @param value
	 *            to set
	 * @param forceAccess
	 *            whether to break scope restrictions using the
	 *            <code>setAccessible</code> method. <code>False</code> will
	 *            only match public fields.
	 */
	private void inject(Field field, Object target, Object value,
			boolean forceAccess) {

		if (field == null) {
			throw new IllegalArgumentException("The field must not be null");
		}

		logger.info(String.format("对 Field %s 进行验证检查", field.getName()));
		if (forceAccess && !field.isAccessible()) {
			field.setAccessible(true);
		} else {
			// 下面这段代码是从org.apache.commons.lang.reflect.FieldUtils
			if (field == null || field.isAccessible()) {
				return;
			}

			if (Modifier.isPublic(field.getModifiers())
					&& isPackageAccess(field.getDeclaringClass().getModifiers())) {
				try {
					field.setAccessible(true);
				} catch (SecurityException e) {
					// ignore in favor of subsequent IllegalAccessException
					logger.severe(e.getMessage());
				}
			}
		}

		try {
			logger.info(String.format("开始对类型  %s 的实例 Field %s 进行依赖注入", target
					.getClass().getName(), field.getName()));
			field.set(target, value);
		} catch (IllegalArgumentException | IllegalAccessException e) {
			if (e.getMessage() != null)
				logger.severe(e.getMessage());
			e.printStackTrace();
		}
	}

	/**
	 * <pre>
	 * 还是抄的,from {@link org.apache.commons.lang.reflect.MemberUtils},原文注释请往下看。
	 * </pre>
	 * 
	 * Learn whether a given set of modifiers implies package access.
	 * 
	 * @param modifiers
	 *            to test
	 * @return true unless package/protected/private modifier detected
	 */
	private boolean isPackageAccess(int modifiers) {
		return (modifiers & (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE)) == 0;
	}

}

/**
 * 被注入对象的宿主
 * 
 * @author lijinting
 * 
 */
class Host {

	private final Logger logger = Logger.getLogger(getClass().getName());

	@Inject
	private Guest guest;

	public void checkMember() {
		logger.info(String.format(
				"checkin' if the member is injected to %s instance correctly",
				getClass().getName()));
		if (guest != null)
			guest.yield();
		else
			logger.info("injection failed. the 'member' member of the Host instance was null.");
	}
}

/**
 * 将要被注入宿主的对象
 * 
 * @author lijinting
 * 
 */
class Guest {

	private final Logger logger = Logger.getLogger(getClass().getName());

	public void yield() {
		logger.info(String.format(
				"if you see this shit, you jus got it right. 凸(O_o)",
				getClass().getName()));
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值