**
IOC/DI(控制反转/依赖注入)学习笔记
**
常规编程对象由程序员自己通过构造方法得到的。ioc控制反转提供了一种新的思想,在程序开始执行时,由代码生成对象并进行集中管理。
- 对象的生成
通过反射机制调用构造方法生成对象。对象之间的依赖关系可以通过注入的方法进行处理。通过学习spring,得到以下方法:可以通过构造方法进行初始化;也可以先反射调用无参构造,通过遍历setter方法对其成员赋值;或者通过对成员加注解的方式完成等等。
spring还提供了配置文件进行解析的方式。将类及所需要的信息和依赖关系等内容写入配置文件中,通过解析配置文件来完成注入。写配置文件虽然很麻烦,但是却可以让用户清楚类与类之间的关系等。
每个对象都是beanFactyory中管理的一个bean,spring有自己的一系列代码为这个bean形成一个beanName,并形成键值对放入map中管理,用户也可以给对象设置别名,spring会将解析出来的别名放入map中管理,通过别名也可以获得对象。spring提供了getBean(…)方法让用户获得对象。
下面记录我自己写的一些代码以及分析:
只实现了对成员加注解进行注入的方法。需要用到包扫描的技术,不是此处的重点。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
//加在类上的注解,说明要将加注解的类交给beanFactory进行管理
public @interface Component {
// name为bean的别名
String name() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
//将方法的返回值作为一个Bean存入BeanFactory中
public @interface Bean {
String name() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
public @interface Autowired {
// 成员或参数可以是八大基本类型,也可以是bean
// 目前只实现到如果value不为空串,那成员只能是八大基本类型,否则不处理。
// 如果value为空串,就认为其是beanFactory中的一个bean
String value() default "";
}
对象有两种scope:singleton(单例)和prototype(原型)
并且有两种加载模式:延迟加载(即懒汉模式) 在getBean()的时候进行初始化和非延迟加载(饿汉模式)
这里只实现简单的单例延迟加载。
以下是对bean的定义:
public class BeanDefinition implements IBeanDefinition {
private Object object;
private String beanName;
private String scope;
public BeanDefinition() {
}
public BeanDefinition(Object object) {
this.object = object;
}
@Override
public Object getObject() {
return this.object;
}
@Override
public void steObject(Object object) {
this.object = object;
}
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
@Override
public String getBeanName() {
return this.beanName;
}
}
定义benadefinition的持有者:
包含有beandefinition、类类型、beanName、代理对象和injection,injection用来判断是否已经被注入,这是处理循环依赖的一个办法,spring中设置了一个是否允许提前曝光的属性(earlyexposure)
这里有代理对象是可以不存在的,由于将IOC和AOP写在了一起,进行强行融合,所以beanFactory中管理的其实是代理对象。对于代理的使用在AOP学习笔记中写出。
- 关于循环依赖:
假设现在又三个类,Class A、Class B、Class C
A中需要一个成员B,B中需要一个成员C,C中需要一个成员A的情况,单例模式可以在A没有完成注入的情况下将
A的对象注入给C;但是对于原型模式,不能这么做,必须将对A生成的对象a1完全实例化之后才能使用,否则如果有其他线程需要使用A生成一个不同对象a2,然而a1并没有完成赋值,这里就会出现大问题。因此循环依赖只有单例模式才能解决,原型模式不能解决循环依赖。在测试的时候会测试循环依赖的情况,代码在最后粘出。
public class BeanDefinitionHolder <T> implements IBeanDefinitionHolder {
// beanDefinition的持有者
private BeanDefinition beanDefinition;
private Class<?> beanClass;
private String beanName;
private T proxy;
private volatile boolean injection;
// TODO 别名数组,暂时不想做
private List<String> alias;
//实例化beanDefiniyionHolder时必须传入BeanDefinition以及beanClass或者className
public BeanDefinitionHolder(BeanDefinition beanDefinition, Class<?> beanClass) {
this.beanDefinition = beanDefinition;
this.beanClass = beanClass;
this.beanName = beanClass.getName();
this.injection = false;
alias = new ArrayList<>();
}
public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName) {
this.beanDefinition = beanDefinition;
this.beanName = beanName;
}
public Object getProxy() {
return this.proxy;
}
public void setProxy(T proxy) {
this.proxy = proxy;
}
@Override
public Class<?> getBeanClass() {
if(this.beanClass != null) {
return this.beanClass;
} else if(this.beanName != null) {
try {
return Class.forName(beanName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public String getBeanName() {
if(this.beanName != null) {
return this.beanName;
} else {
return this.beanClass.getName();
}
}
@Override
public Object getObject() {
return this.beanDefinition.getObject();
}
@Override
public boolean isInjection() {
return this.injection;
}
@Override
public void changeInjection() {
this.injection = true;
}
@Override
public String toString() {
return "BeanDefinitionHolder{" +
"beanName='" + beanName + '\'' +
'}';
}
}
接下来是Bean工厂,beanFactory中实现了对bean的管理。
Spring中定义了FactoryBean,用以区分普通的bean。
!!!这里理解的不是很清楚,大概的意思应该是在factoryBean中有getObject()方法,可以用来返回代理以及织入拦截器。(以后对源码阅读的更加深入后进行修改)
采用懒汉模式,因此在包扫描时,只是读入基本信息,对beanDefinitionHolder进行填充并存入beanDefinitionHolderMap中,在geBean()时,首先在beanMap中get(),如果返回值不为null,则返回结果;如果返回null,则在BeanDefinidionHolderMap中找对应的beanDefinitionHolder,如果返回值依然是null,则应该抛出异常;如果得到了对应的beanDefinitionHolder,则根据beanDefinitionHoler生成bean,并返回。
初始化时先从beanDefinitionHolder中得到基本信息,然后通过反射机制处理其带有注解的成员和方法,完成后返回对象。
public abstract class BeanFactory implements IBeanFactory {
// beanMap存储的全是代理
private volatile static Map<String, Object> beanMap;
// aliasMap是别名以及beanName形成的键值对,代码中并没有进行处理
private volatile static Map<String, String> aliasMap;
private volatile static Map<String, BeanDefinitionHolder> beanDefinitionHolderMap;
private final static Object object = new Object();
private final static Object createBeanObject = new Object();
static {
beanMap = new ConcurrentHashMap<>();
aliasMap = new ConcurrentHashMap<>();
beanDefinitionHolderMap = new ConcurrentHashMap<>();
}
private <T> T cglProxy(BeanDefinitionHolder beanDefinitionHolder) {
String beanName = beanDefinitionHolder.getBeanName();
T proxy = (T) beanMap.get(beanName);
if (proxy != null) {
return proxy;
}
synchronized (object) {
proxy = (T) beanMap.get(beanName);
if (proxy == null) {
ProxyBulider proxyBulider = new ProxyBulider(beanDefinitionHolder);
proxy = (T) proxyBulider.getCGLProxy(beanDefinitionHolder);
}
}
return (T) proxy;
}
private <T> T jdkProxy(BeanDefinitionHolder beanDefinitionHolder) {
String beanName = beanDefinitionHolder.getBeanName();
T proxy = (T) beanMap.get(beanName);
if (proxy != null) {
return proxy;
}
synchronized (object) {
proxy = (T) beanMap.get(beanName);
ProxyBulider proxyBulider = new ProxyBulider(beanDefinitionHolder);
proxy = (T) proxyBulider.getJDKProxy(beanDefinitionHolder);
}
return proxy;
}
// 根据Spring的思路,如果该类实现了接口,则优先获取jdk代理
private <T> T doCreateProxy(BeanDefinitionHolder beanDefinitionHolder, Class<?> klass) throws Exception {
T proxy;
if (klass.getInterfaces().length > 0) {
proxy = cteateJDKProxy(beanDefinitionHolder);
} else {
proxy = createCGLProxy(beanDefinitionHolder);
}
beanDefinitionHolder.setProxy(proxy);
beanDefinitionHolder.changeInjection();
initBean(beanDefinitionHolder);
beanMap.put(klass.getName(), proxy);
return proxy;
}
private void initBean(BeanDefinitionHolder beanDefinitionHolder) throws Exception {
Class<?> klass = beanDefinitionHolder.getBeanClass();
Object object = beanDefinitionHolder.getObject();
Field[] fields = klass.getDeclaredFields();
for (Field field : fields) {
autowiredInjectionField(object, field);
}
Method[] methods = klass.getDeclaredMethods();
for (Method method : methods) {
autowiredMethod(method, object);
}
}
// DI主要针对的是复杂类类型(用户自定义类类型等),因此要求注入八大基本类型时注解必须要写value属性
// 否则将不进行处理,需要抛出异常
// 如果不是八大基本类型,则默认为是BeanFactory中的一个bean,即注入的是代理
private Object autowiredInjectionField(Object object, Field field) throws Exception {
if (field.isAnnotationPresent(Autowired.class)) {
Autowired autowired = field.getAnnotation(Autowired.class);
Class<?> fieldClass = field.getType();
Object fieldObject;
if (fieldClass.isPrimitive()) {
String value = autowired.value();
if (value.length() <= 0) {
throw new PrimitiveMustHaveValueAttributeException("八大基本类型的成员或参数" +
field + "必须含有value属性");
}
// 这里将String类型的value转换为对应的八大基本类型并注入
fieldObject = BeanUtils.stringToPrimitive(value, fieldClass);
} else {
// 首先从BeanMap中获取,如果取不到,意味着循环依赖,其依赖的bean的代理还没有获取到,则处理循环依赖
fieldObject = getBean(fieldClass.getName());
}
field.setAccessible(true);
field.set(object, fieldObject);
}
return object;
}
// Method上加Bean注解的意思在该方法的返回值为BeanFactory中的一个Bean,在初始化类时执行
// 需要先注入成员,在执行方法,因为考虑的该方法中可能需要用到某些成员的值
// 方法执行完毕后要将其返回值加入到BeanMap中
// 自执行方法如果有参数,则每个参数都应该加上相应的注解,
// 否则无法对其参数进行赋值,应该抛出异常
// 并且参数的返回值类型不能为void,这里强行规定返回值类型也不能是八大基本类型
// TODO 这里并不能处理多个方法返回值都相同的情况
private Object autowiredMethod(Method method, Object object) throws BeanMethodReturnTypeIsErrorException {
if (method.isAnnotationPresent(Bean.class)) {
Bean bean = method.getAnnotation(Bean.class);
String name = bean.name();
Class<?> methodClass = method.getReturnType();
if (methodClass.equals(void.class) || methodClass.isPrimitive() ||
method.getParameters().length > 0) {
throw new BeanMethodReturnTypeIsErrorException("Method" + method + "返回值类型不能是"
+ methodClass);
}
// 先判断是否加载了BeanDefinition,如果没有,先加载
// TODO 这里先不处理有参数的方法,是否处理以后视情况而定
String beanName = methodClass.getName();
beanMap.put(beanName, doAutowiredMethod(object, method));
if (name.length() > 0) {
aliasMap.put(name, beanName);
}
}
return object;
}
private Object doAutowiredMethod(Object object, Method method) {
try {
return method.invoke(object);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
private Object doCreateBean(Object proxy, String beanName, BeanDefinitionHolder beanDefinitionHolder) throws Exception {
proxy = beanMap.get(beanName);
if (proxy == null) {
synchronized (createBeanObject) {
proxy = beanMap.get(beanName);
if (proxy == null) {
// 通过injection来判断该Bean是否正在创建中,以此来解决循环依赖
if (!beanDefinitionHolder.isInjection()) {
proxy = createBean(beanDefinitionHolder);
return proxy;
} else {
return beanDefinitionHolder.getObject();
}
}
}
}
return proxy;
}
// 如果进行到这一步,获取的一定是代理
@Override
public <T> T createBean(BeanDefinitionHolder beanDefinitionHolder) throws Exception {
Class<?> beanClass = beanDefinitionHolder.getBeanClass();
return doCreateProxy(beanDefinitionHolder, beanClass);
}
@Override
public <T> T createCGLProxy(BeanDefinitionHolder beanDefinitionHolder) {
return cglProxy(beanDefinitionHolder);
}
@Override
public <T> T cteateJDKProxy(BeanDefinitionHolder beanDefinitionHolder) {
return jdkProxy(beanDefinitionHolder);
}
@Override
public void setBeanDefinitionHolder(BeanDefinitionHolder beanDefinitionHolder) {
if (!beanDefinitionHolderMap.containsValue(beanDefinitionHolder)) {
beanDefinitionHolderMap.put(beanDefinitionHolder.getBeanName(), beanDefinitionHolder);
}
}
@Override
public BeanDefinitionHolder getBeanDefinitionHolder(String beanName) {
return beanDefinitionHolderMap.get(beanName);
}
// 创建bean时需要考虑到循环依赖的情况,这里是通过对其成员进行注入解决的
// TODO 以后还应该提供构造函数参数解析的方法
@Override
public <T> T getBean(String name) throws Exception {
String beanName = name;
// 首先从beanMap中获取,因为有可能是扫描时某个方法的返回值,也有可能是某个已经被加载的bean
Object proxy = beanMap.get(beanName);
if (proxy != null) {
return (T) proxy;
}
// 如果获取不到,则找beanDefinitionHolder准备初始化bean
BeanDefinitionHolder beanDefinitionHolder = beanDefinitionHolderMap.get(beanName);
if (beanDefinitionHolder == null) {
beanName = aliasMap.get(beanName);
if (beanName == null) {
beanName = name;
}
beanDefinitionHolder = beanDefinitionHolderMap.get(beanName);
}
// 如果beanDefinitionHolder == null,则应该抛出异常
if (beanDefinitionHolder == null) {
throw new BeanDefinitionHolderIsNotExistException("未扫描到相关的Bean");
}
proxy = doCreateBean(proxy, beanName, beanDefinitionHolder);
return (T) proxy;
}
void addAlias(String beanName, String alias) {
aliasMap.put(beanName, alias);
}
public abstract void addBeanDefinitionholder(Class<?> klass);
}
默认bean工厂,执行包扫描以及beanDefinitionHolder的初始化形成beanDefinitionHolderMap,并提供getBean()的方法。
下面的代码给出getProxy()和getObject()方法用来实现getBean的功能。
spring中对bean工厂有更加详细的划分,这里不做出模仿。
public class DefaultBeanFactory extends BeanFactory implements IBeanBuilder {
public void packageScan(String packagePath) {
new PackageScanner() {
@Override
public void dealClass(Class<?> klass) {
dealKlass(klass);
}
}.packageScanner(packagePath);
}
private void dealKlass(Class<?> klass) {
if(!klass.isAnnotationPresent(Component.class)) {
return;
}
Component component = klass.getAnnotation(Component.class);
String alias = component.name();
// 为了方便初始化,这里统一使用无参构造,对于初始化时需要传入的参数等,使用对成员进行注入的方法
// 这里先进行包扫描形成对应的beanDefinitionMap,为以后getBean时取得Bean的所有信息打好基础
// Spring中对于BeanDefinition的定义复杂,这里做的是极为简陋的
// 直接使用无参构造及逆行初始化
// TODO 全部采取懒汉模式所以这里不用进行实例化操作,以后应该加上饿汉模式,拦截器是通过相关的代理加上的,
// 在形成代理时是否已经有了相应的拦截器链并不重要,但是在程序启动之前必须对拦截器类进行扫描
addBeanDefinitionholder(klass);
if(alias.length() > 0) {
addAlias(klass.getName(), alias);
}
}
@Override
public Object getObject(Class<?> klass) {
return getBeanDefinitionHolder(klass.getName()).getObject();
}
@Override
public <T> T getproxy(Class<?> klass) {
try {
return getBean(klass.getName());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public void addBeanDefinitionholder(Class<?> klass) {
BeanDefinition beanDefinition = new BeanDefinition();
try {
Object object = klass.newInstance();
beanDefinition.steObject(object);
beanDefinition.setBeanName(klass.getName());
BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, klass);
setBeanDefinitionHolder(beanDefinitionHolder);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
- 测试:
@Component
public class A {
@Autowired
private B b;
public A() {
}
public void setB(B b) {
this.b = b;
}
public B getB() {
return b;
}
public void fun(B b) throws Exception {
// System.out.println("自动注入的num:" + this.num);
System.out.println("这是fun方法");
throw new Exception();
}
@Override
public String toString() {
return "这是A - >B\n" + b;
}
}
@Component
public class C {
@Autowired
private A a;
public C() {
}
public void setA(A a) {
this.a = a;
}
public A getA() {
return a;
}
public void fun() {
}
@Override
public String toString() {
return "这是C - >A";
}
}
public class Demo {
public static void main(String[] args) {
DefaultBeanFactory defaultBeanFactory = new DefaultBeanFactory();
defaultBeanFactory.packageScan("com.xxy.test");
B b = new B();
b.setNum(0);
A a = defaultBeanFactory.getproxy(A.class);
System.out.println(a);
}
}
结果:
这是A - >B
这是B - >C
这是C - >A
Process finished with exit code 0
这是在学习了ioc之后做出的一些尝试性练习,如果有错误的地方还请各位大佬给予指正,谢谢!