【Java】模仿Spring 实现 依赖注入

【Java】模仿Spring 实现 依赖注入

在java编程里面,我们常常在一个类里面要调用另一个类的方法,常常会new一个对象,这样使得代码看起来不整齐,不美观!
为了编程的极大方便,因此在Spring里面提出来依赖注入,也就是控制反转,这样子可以直接让框架来帮我们实现对于对象的注入
现在我们自己模仿实现以下依赖注入;
先来给出三个注解:
@Autowired
它可以对类成员变量进行注解 完成自动装配的工作。
Bean
@Bean是放在方法的注释,它会告诉Spring这个方***返回一个对象,
该对象要注册为Spring应用上下文中的bean。
Component
@component: 把普通pojo实例化到spring容器中,
相当于配置文件中的
它泛指各种组件,就是说当我们的类不属于各种归类的时候
(不属于@Controller、@Services等的时候),我们就可以
使用@Component来标注这个类。

@Retention(RUNTIME)
@Target(FIELD)
public @interface Autowired {
	String name() default "";
}

@Retention(RUNTIME)
@Target(TYPE)
public @interface Component {
	String name() default "";
}

下面给出一个 类里面定义了 该类是否被定义,以及 给出元数据类和对象

public class BeanDefinition {
	private Class<?> klass;
	private Object object;
	private boolean inject;
//	是否被注入了
	
	BeanDefinition() {
		this.inject = false;
	}

	boolean isInject() {
		return inject;
	}

	void setInject(boolean inject) {
		this.inject = inject;
	}

	Class<?> getKlass() {
		return klass;
	}

	void setKlass(Class<?> klass) {
		this.klass = klass;
	}

	Object getObject() {
		return object;
	}

	void setObject(Object object) {
		this.object = object;
	}

	@Override
	public String toString() {
		return klass.getSimpleName() + " : " + object;
	}
	
}

下面进行包扫描
扫描有相关注解的类,进行是否 注入的检测,要是已经注入则不用重复调用,并且采用了懒汉模式等待相关的bean 获得了才进行注入
进行注入时
getBean 的作用就是获得defination里面的 object
并且这个方法和 InjectProperties相互调用 所以能够实现深度注入
但是还没有解决循环依赖注入
用来存放对象实例的一个静态map(单例)(键为ClassName的字符串,值为BeanDefinition的一个实例)

public class BeanFactory {
        	private static final Map<String, BeanDefinition> beanPool;
	
	static {
		beanPool = new HashMap<String, BeanDefinition>();
	}
		
	public BeanFactory() {
	}
	
//      包扫描(扫描那个包下哪些对象需要注入)
	public static void scanBeanByPackage(String packageName) {
		new PackageScanner() {
			
			@Override
			public void dealClass(Class<?> klass) {
				if (klass.isPrimitive()
					|| klass.isArray()
					|| klass.isEnum()
					|| klass.isAnnotation()
					|| klass.isInterface()
					|| !klass.isAnnotationPresent(Component.class)) {
					return ;
				}
				Object object = null;
				try {    
                                        //通过类名用反射机制得到一个实例(但里面的成员为null)
					object = klass.newInstance();
					BeanDefinition bd = new BeanDefinition();
					bd.setKlass(klass);
					bd.setObject(object);
					
					beanPool.put(klass.getName(), bd);
				} catch (InstantiationException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}.packageScanner(packageName);
	}
	private void injectProperties(BeanDefinition bd) {
		System.out.println(" 进行注入");
		Class<?> klass = bd.getKlass();
		Object object = bd.getObject();
		System.out.println(klass);
		Field[] fileds = klass.getDeclaredFields();
		for (Field field : fileds) {
			if (!field.isAnnotationPresent(Autowired.class)) {
				continue;
			}
			// TODO 应该先对inject进行判断,若为true,表示该对象已经完成注入;
						field.setAccessible(true);
			Object value = getBean(field.getType());
			if (value == null) {
				throw new HasNoBeanException("类["
						+ klass.getName() +  "]的成员[" + field.getName() +  "]没有对应的Bean");
			}
			try {
				field.set(object, value);
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		bd.setInject(true);
	}
	
	@SuppressWarnings({ "null", "unchecked" })
	public <T> T getBean(String className) {
		BeanDefinition bd = getBeanDefinition(className);
		if (bd == null) {
			throw new HasNoBeanException("类["
					+ className +  "]没有对应的Bean");
		}
		Object object = bd.getObject();

		if (!bd.isInject()) {
			injectProperties(bd);
		}
		
		return (T) object;
	}
	public <T> T getBean(Class<?> className) {
		return getBean(className.getName());
	}
	
	BeanDefinition getBeanDefinition(String className) {
		return beanPool.get(className);
	}
	
	BeanDefinition getBeanDefinition(Class<?> className) {
		return beanPool.get(className.getName());
	}
}


	

这样的方式 实现了注入依赖 当A里面有 B , B中有C时,
A先getBean()发现没被注入 就先进行 injectProperties()
当进行 注入时又会调用B的getbean ()( Object value = getBean(field.getType());
)方法 这时 发现 B没被注入好,
又进行injectProperties()方法的这时 又会调用C的getbean () (Object value = getBean(field.getType()); )发现C 无需注入 inject为true
并且将C注入 这样就可以getbean时返回一个 被注入的B
既然B已经被注入 那么A最终也能实现注入!
那么我们在正常使用工具时当然是 先使用 B的getBean() 最后使用 A的getBean()

给出 Complex类

@Component
public class Complex {
	private double real;
	private double vir;
	
	public Complex() {
	}

	public double getReal() {
		return real;
	}

	public void setReal(double real) {
		this.real = real;
	}

	public double getVir() {
		return vir;
	}

	public void setVir(double vir) {
		this.vir = vir;
	}

	@Override
	public String toString() {
		return "(" + real + ", " + vir + ")";
	}

}

给出测试:
BeanFactory.scanBeanByPackage("com.hjz.spring_imitate.some_class");
		BeanFactory.scanBeanByPackage("com.hjz.spring_imitate.other_class");
		BeanFactory beanFactory = new BeanFactory();
		
		Complex c1 = beanFactory.getBean(Complex.class.getName());
		Complex c2 = beanFactory.getBean(Complex.class.getName());
		System.out.println(c2 == c1);

最终 会输出 注入
并且输出true   因为是单例的!

这样我们就完成了依赖注入!

全部评论

相关推荐

11-21 11:26
已编辑
门头沟学院 前端工程师
Apries:这个阶段来说,很厉害很厉害了,不过写的简历确实不是很行,优势删掉吧,其他的还行
点赞 评论 收藏
分享
冲芭芭拉鸭:你这图还挺新,偷了。
投递美团等公司10个岗位
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务