手写依赖注入(注解方式)
- 先谈谈什么是依赖注入?
- 依赖注入也叫DI(Dependency Injection)是对象之间的依赖关系靠某一种手段注入.可能一说到DI就不由自主的想到Spring,那又会老生常谈了:Spring是什么?很多人会说Spring是IOC和AOP(手动滑稽☻),当然这都是初学者一些回答,不能说这些回答是错的,但是再往里探究一层,像Spring的IOC容器具体是什么?Spring依赖注入默认是怎么保证单例的?
- 对于上述问题大部分java开发也是清楚的,不论是查阅资料得知还是debug源码探究都是了解的方式,开发人员使用这些框架时,一般不通过new创建对象,而是由容器管理对象的创建,对于依赖的服务,也不需要自己管理,而是使用注解表达依赖关系。这么做的好处有很多,代码更为简单,也更为灵活.
下面手写一个简单依赖注入: 既然是注解方式那么久先定义注解:
/***
* Description <br>
* @author shi.yuwen <br>
* 普通方式注入
**/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SimpleInject {
}
/***
* Description <br>
* @author shi.yuwen <br>
* 单例方式注入
**/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface SimpleSingleInject {
}
注解的驱动类
/**
* <Description> <br>
*
* @author shi.yuwen<br>
* @version 1.0<br>
* @taskId: <br>
* @createDate 2020/07/16 16:19 <br>
* @see date20200716annotation <br>
*/
public class SimpleContainer {
public static Map<Class<?>, Object> instances = new ConcurrentHashMap<>();
public static <T> T getSingleInstance(Class<T> cls) {
try {
//判断是否走单例
if (!cls.isAnnotationPresent(SimpleSingleInject.class)){
return getInstance(cls);
}
Object obj = instances.get(cls);
if (null != obj) {
return (T)obj;
}
//使用类锁锁代码块
synchronized (cls) {
if (null == instances.get(cls)) {
obj = getInstance(cls);
instances.put(cls, obj);
}
}
return (T)obj;
}
catch (Exception e) {
throw new RuntimeException();
}
}
public static<T> T getInstance (Class<T> cls){
try {
T obj = cls.newInstance();
//返回本类申明的字段包括非public,不包括父类
Field[] declaredFields = cls.getDeclaredFields();
for (Field f : declaredFields) {
//判断字段是否包含指定注解类型
if (f.isAnnotationPresent(SimpleInject.class)) {
//判断字段是否为私有
if (!f.isAccessible()) {
f.setAccessible(true);
}
//再次递归调用赋值
f.set(obj, getInstance(f.getType()));
}
}
return obj;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
写三个服务类表示依赖关系:
public class ServiceA {
@SimpleInject
public ServiceB serviceB;
public void callB () {
serviceB.action();
}
}
@SimpleSingleInject
public class ServiceB {
@SimpleInject
ServiceC serviceC;
public void action () {
serviceC.action();
}
}
@SimpleSingleInject
public class ServiceC {
public void action() {
System.out.println("I am C");
}
}
编写测试类(装载ServiceA查看是否能依赖注入ServiceB,ServiceC)
public class TestMain {
public static void main(String[] args) {
//ServiceA serviceA = SimpleContainer.getInstance(ServiceA.class);
ServiceA serviceA = SimpleContainer.getSingleInstance(ServiceA.class);
serviceA.callB();
}
}
测试结果: