首先要明确一下,类与类之间有依赖关系,我们这里解决的依赖是指一种弱依赖。这样直接说弱依赖,你可能不太理解是什么意思,我举个例子说明一下弱依赖的场景。
比如,对于这样的场景:
对于两个类A、B,A弱依赖于B(我们可以这样理解,创建A的实例不需要B来参加,但是A实现功能需要调用B的方法),A里面有B成员的实例成员b(未初始化的),但是b不在类A的构造方法里,所以通过构造方法来创建A的实例a,如果不做额外处理,a里面的b成员肯定为null,那么在a实现某一功能需要调用b的方法时,就会报出空指针异常!。
对于此,这里我们提出了依赖注入的概念,即对a的成员b从外界注入一个类B的实例,这样a就可以完成需要b调用方法来实现的某一功能。
需要指明的是,考虑到一些时间上的成本,我们这里是采用懒汉模式(需要的时候才注入)来实现的,而不是饿汉模式(不管需不需要,都注入)。
1.给平凡的类以及需要被注入的成员加标识的注解;
2.通过包扫描,将这些平凡的类的对象组织到一个容器里面。
3.当被注解的成员需要注入时,调用容器提供的注入方法。
当出现以下情况时,会产生循环依赖,为了避免这种情况,我们给封装平凡的类(如A、B、C)相关信息的BeanDefinition类里面加上了inject属性。
第一个注解Component用于标识平凡的类,以下是注解的具体内容。
package com.mec.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 "";
}
第二个注解Autowired用于标识需要注入的成员,以下是注解的具体内容。
package com.mec.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 "";
}
我们把平凡的类的元数据类、对象、以及判断是否被注入的属性封装成一个BeanDefinition类,如下图所示。
package com.mec.spring_imitate.core;
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;
}
}
然后接着,我们把BeanDefinition按照某种对应关系组织到类BeanFactory的Map
package com.mec.spring_imitate.core;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import com.mec.orm.core.PackageScanner;
import com.mec.spring_imitate.annotation.Autowired;
import com.mec.spring_imitate.annotation.Bean;
import com.mec.spring_imitate.annotation.Component;
public class BeanFactory {
private static final Map beanPool;//单例实现,只需要一份就够了。
static {
beanPool = new HashMap();
}
public BeanFactory() {
}
public void scanBeanByPackage(String packageName) {
new PackageScanner() {//包扫描
@Override
public void dealClass(Class> klass) {
if (klass.isPrimitive()//八大基本类型
|| klass.isInterface()//接口
|| klass.isAnnotation()//注解
|| klass.isEnum()//枚举
|| klass.isArray()//数组
|| !klass.isAnnotationPresent(Component.class))//不包含Component注解的类
{
return;
}
Object object = null;
try {//这样的设置方法保证了注入的对象是单例的。
object = klass.newInstance();
BeanDefinition bd = new BeanDefinition();
bd.setKlass(klass);
bd.setObject(object);
//把被Component注解的类形成的对应关系加入到beanpool容器里
beanPool.put(klass.getName(), bd);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}.packageScanner(packageName);
}
boolean hasClass(String className) {
return beanPool.containsKey(className);
}
BeanDefinition getBeanDefinition(String klassName) {
return beanPool.get(klassName);
}
BeanDefinition getBeanDefinition(Class> klass) {
return getBeanDefinition(klass.getName());
}
private void injectProperties(BeanDefinition beanDefinition) throws RuntimeException {
Class> klass = beanDefinition.getKlass();
Object object = beanDefinition.getObject();
Field[] fields = klass.getDeclaredFields();
for (Field field : fields) {
if (!field.isAnnotationPresent(Autowired.class)) {//如果没有需要注入的注解标记的成员,则跳过。
continue;
}
field.setAccessible(true);//设置成员可访问
Object value = getBean(field.getType());//获取被@Autowired标记的成员的BeanDefinition
if (value == null) {//如果获取的被@Autowired标记的成员的BeanDefinition为null,则说明没有对应的BeanDefinition
throw new HasNoBeanException("类[" + klass.getName()
+ "]的[" + field.getName()
+ "]成员没有对应的BeanDefinition!");
}
try {
field.set(object, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
@SuppressWarnings("unchecked")
public T getBean(String klassName) throws RuntimeException {
BeanDefinition bd = getBeanDefinition(klassName);
if (bd == null) {
return null;
}
Object result = bd.getObject();
if (!bd.isInject()) {//如果没有被注入,则设置为注入,这样可以解决循环依赖问题
bd.setInject(true);
injectProperties(bd);//注入
}
return (T) result;
}
public T getBean(Class> klass) throws RuntimeException {
return getBean(klass.getName());
}
}
现在开始测试,首先测试单例以及异常处理:
被测试的平凡的类
Complex类,具体内容如下。
package com.mec.spring_imitate.some_class;
import com.mec.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 + ")";
}
}
ClassOne类,具体内容如下。
package com.mec.spring_imitate.some_class;
import com.mec.spring_imitate.annotation.Autowired;
import com.mec.spring_imitate.annotation.Component;
@Component
public class ClassOne {
@Autowired
private Complex complex;
@Autowired
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 "ClassOne [complex=" + complex + ", str=" + str
+ ", point=" + point + "]";
}
}
Point类,具体内容如下。
package com.mec.spring_imitate.some_class;
public class Point {
private int row;
private int col;
private Complex complex;
public Point() {
}
public Point(Complex complex) {
this.complex = complex;
}
int getRow() {
return row;
}
void setRow(int row) {
this.row = row;
}
int getCol() {
return col;
}
void setCol(int col) {
this.col = col;
}
public Complex getComplex() {
return complex;
}
public void setComplex(Complex complex) {
this.complex = complex;
}
@Override
public String toString() {
return "[" + row + ", " + col + "]";
}
}
测试类和测试结果截图一:
package com.mec.spring_imitate.test;
import com.mec.spring_imitate.core.BeanFactory;
import com.mec.spring_imitate.some_class.ClassOne;
import com.mec.spring_imitate.some_class.Complex;
public class Demo {
public static void main(String[] args) {
BeanFactory.scanBeanByPackage("com.mec.spring_imitate.some_class");
BeanFactory beanFactory = new BeanFactory();
Complex c1 = beanFactory.getBean(Complex.class.getName());
Complex c2 = beanFactory.getBean(Complex.class.getName());
System.out.println(c2 == c1);
ClassOne classOne = beanFactory.getBean(ClassOne.class);
ClassOne classTwo = beanFactory.getBean(ClassOne.class);
System.out.println(classOne + "\n" + classTwo);
}
}
/*
输出结果:
true
Exception in thread "main" com.mec.spring_imitate.core.HasNoBeanException: 类[com.mec.spring_imitate.some_class.ClassOne]的[point]成员没有对应的BeanDefinition!
at com.mec.spring_imitate.core.BeanFactory.injectProperties(BeanFactory.java:113)
at com.mec.spring_imitate.core.BeanFactory.getBean(BeanFactory.java:135)
at com.mec.spring_imitate.core.BeanFactory.getBean(BeanFactory.java:142)
at com.mec.spring_imitate.test.Demo.main(Demo.java:16)
*/
测试循坏依赖:
修改Complex类(增加一个Point类型的成员,并加上注解Autowired),如下所示
package com.mec.spring_imitate.some_class;
import com.mec.spring_imitate.annotation.Autowired;
import com.mec.spring_imitate.annotation.Component;
@Component
public class Complex {
private double real;
private double vir;
@Autowired
private Point point;
//其余内容同上
@Override
public String toString() {
return "(" + real + ", " + vir + "), Point:" + point;
}
}
再修改Point类(增加一个Complex类型的成员,并增加注解Autowired),如下所示
package com.mec.spring_imitate.some_class;
import com.mec.spring_imitate.annotation.Autowired;
import com.mec.spring_imitate.annotation.Component;
@Component
public class Point {
private int row;
private int col;
@Autowired
private Complex complex;
//其余内容同上
}
测试类和测试结果截图二:
package com.mec.spring_imitate.test;
import com.mec.spring_imitate.core.BeanFactory;
import com.mec.spring_imitate.some_class.ClassOne;
import com.mec.spring_imitate.some_class.Complex;
import com.mec.spring_imitate.some_class.Point;
public class Demo {
public static void main(String[] args) {
BeanFactory beanFactory = new BeanFactory();
beanFactory.scanBeanByPackage("com.mec.spring_imitate.some_class");
Complex c1 = beanFactory.getBean(Complex.class.getName());
System.out.println(c1);
Point point = beanFactory.getBean(Point.class);
System.out.println(point);
ClassOne classOne = beanFactory.getBean(ClassOne.class);
System.out.println(classOne);
}
}
/*
输出结果:
(0.0, 0.0), Point:[0, 0]
[0, 0]
ClassOne [complex=(0.0, 0.0), Point:[0, 0], str=null, point=[0, 0]]
*/
总的来说,我们的测试结果还是令人满意的,我们的BeanFactory里面提供的getBean方法还是能实现弱依赖注入的,并且成功的解决了循环依赖问题。
对于有些类,比如已经在jar包里面的类,我们是无法加注解的,这种方式行不通,那么我们怎么处理呢?
因此,敬请期待下一篇Spring 依赖注入——模拟实现(二)(方法注入)。
下载地址:https://github.com/dx99606707/depository/blob/master/Spring模拟实现对象注入及循环依赖的处理.rar