SpringFramework--依赖注入模拟详解
为什么有依赖注入:平常的Java开发中,程序员在某个类中需要依赖其它类的方法。
我们通常是new一个依赖类再调用类实例的方法set进去,这种开发存在的问题是new的类实例不好统一管理。
所以Spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过Spring容器帮我们new指定实例并且将实例注入到需要该对象的类中。
依赖注入的另一种说法是"控制反转"。通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员。
而控制反转是指new实例工作不由我们程序员来做而是交给Spring容器来做。
在这里为了使大家看的更加清晰我们用注解的方法去模拟:(注意:通过Spring创建的对象默认是单例)
首先给出两个注解类:
- Autowired注解类:用来注解依赖类成员,表示该成员需要注入;
- Component注解类:用来注解哪个类里面有成员有Atuowired注解;
Autowired 类
package com.htt.spring_imitate.annotation;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(FIELD)
public @interface Autowired {
String name() default "";
}
Componet 类
package com.htt.spring_imitate.annotation;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(TYPE)
public @interface Component {
String name() default "";
}
此时我们要给出一个类BeanDefinition:此类是用来产生一个Bean(即一个平凡类)的实例对象的;
package com.htt.spring_imitate.core;
public class BeanDefinition {
private Class<?> klass;
private Object object;
// 确定此类是否已近被注入过
private boolean inject;
protected Class<?> getKlass() {
return klass;
}
protected void setKlass(Class<?> klass) {
this.klass = klass;
}
protected Object getObject() {
return object;
}
protected void setObject(Object object) {
this.object = object;
}
protected boolean isInject() {
return inject;
}
protected void setInject(boolean inject) {
this.inject = inject;
}
@Override
public String toString() {
return "[klass=" + klass.getSimpleName() + ", object=" + object + "]";
}
}
接下来就可以去建造一个模拟的Spring工厂BeanFactory,可以根据Class类得到一个实例对象(如果这个类中有还未注入的,会自动注入)。这个BeanFactory采用懒汉模式即等到相关Bean被获取后才去注入。
(其中包扫描的技术可以看这个链接包扫描技术 )
其中可以通过两种方法得到实例对象,我们给的返回值均为泛型类型
- public <T> T getBean(String className) ;
- public <T> T getBean(Class<?> className);
package com.htt.spring_imitate.core;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.HTT.Util.PackageScanner;
import com.htt.spring_imitate.annotation.Autowired;
import com.htt.spring_imitate.annotation.Bean;
import com.htt.spring_imitate.annotation.Component;
import com.htt.spring_imitate.exception.HasNoBeanException;
public class BeanFactory {
//用来存放对象实例的一个静态map(键为ClassName的字符串,值为BeanDefinition的一个实例)
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类有成员A)如果getBean(A.class)会出现这样的循环,我们这里采用的形式是给BeanDefinition类一个成员boolean inject;它不仅仅可以判断是否注入,也可以处理循环依赖,我们可以先给A的BeanDefinition的inject为true;在B的成员BeanDefinition的inject里判断时可以结束循环依赖。
下面我们给一个Test类来测试一下:("com.htt.spring_imitate.some_class"这个包的东西在后面给出)
package com.htt.spring_imitate.test;
import com.htt.spring_imitate.core.BeanFactory;
import com.htt.spring_imitate.some_class.ClassOne;
public class Test{
public static void main(String[] args) {
// 扫描这个包下面类
BeanFactory.scanBeanByPackage("com.htt.spring_imitate.some_class");
BeanFactory beanFactory = new BeanFactory();
ClassOne co1 = beanFactory.getBean(ClassOne.class);
ClassOne co2 = beanFactory.getBean(ClassOne.class);
System.out.println(co1);
System.out.println(co2);
System.out.println("判断是不是单例模式" + (co1 == co2));
}
}
结果如下:
ClassOne 类
package com.htt.spring_imitate.some_class;
import com.htt.spring_imitate.annotation.Autowired;
import com.htt.spring_imitate.annotation.Component;
@Component
public class ClassOne {
@Autowired
private Complex complex;
private Point point;
private String str;
public ClassOne() {
}
public Complex getComplex() {
return complex;
}
public void setComplex(Complex complex) {
this.complex = complex;
}
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "[complex=" + complex + ", str=" + str
+ ", point=" + point + "]";
}
}
Complex 类
package com.htt.spring_imitate.some_class;
import com.htt.spring_imitate.annotation.Component;
@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 + ")";
}
}