下午花了点没事做的时间做了一个利用反射进行依赖注入的范例,通过这个代码可以大概知道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()));
}
}