【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 因为是单例的!
这样我们就完成了依赖注入!