在上一篇文章中我们已经对那些无参实体bean进行了一个生成到map容器内来实现模拟spring的ioc容器,但是事实上我们的bean实体其实很多都是相互依赖的情况,比如某个service1依赖了另外的service2,那如果要生成service1我们就必须把service2注入到service1中,而通常我们将某某属性注入一般的就是两种方式
DI:Dependency injection 依赖注入
- 构造函数/工厂方法 存需要传递对应的依赖类
- 成员属性所需对应的依赖类
通过构造函数/工厂方法 实现属性注入
BeanReference的引出
要知道要想产生一个对象可以通过构造方法实现,同理假设service1依赖了service2,其中service2是我们spring的bean,那就意味着我们的service1含有service2的成员变量,那作为成员变量,我们要通过何种结构才能让我们的service2脱颖而出或者说让我们知道它是spring的bean类型,而不是我们通常的基本数据类型或者其它数据类型。
为Bean依赖定义一种数据类型(BeanReference),bean工厂在构造Bean实例时,遍历判断参数是否是BeanReference,如是则替换为依赖的bean实例。
/**
* @author heian
* @date 2021/2/17 3:00 下午
* @description 成员变量为ioc容器的依赖引用
*/
@Getter
public class BeanReference {
private String beanName;
public BeanReference(String beanName) {
this.beanName = beanName;
}
}
BeanDefinition的改造
因为我们知道要想通过构造函数来创建一个对象就必须知道它的构造函数,而构造函数是由无参构造和有参构造并且可以重载,所以我们创建一个bean就必须得知道它有哪些成员变量也就是我们构造函数中的实参。所以BeanDefinition中就必须要增加获得构造参数值的接口。
实现BeanFactory中实现构造参数依赖注入
第一:首先需要把bean定义中的构造参数引用转为真实的值,在DefaultBeanFactory中增加一个方法来干这事。
/**
* 字段中包含其它引用类型字段:如ioc的bean字段、集合等
*/
private Object[] getRealValues(List<?> args) throws Exception {
if(CollectionUtils.isEmpty(args)) {return null;}
Object[] values = new Object[args.size()];
Object v = null;
for(int i = 0; i < args.size(); i++){
Object rv = args.get(i);
if(rv == null) {
v = null;
}else if (rv instanceof BeanReference){
v = doGetBean(((BeanReference) rv).getBeanName());
}else if (rv instanceof Object[]) {
// TODO 处理集合中的bean引用
} else if (rv instanceof Collection) {
// TODO 处理集合中的bean引用
} else if (rv instanceof Properties) {
// TODO 处理properties中的bean引用
} else if (rv instanceof Map) {
// TODO 处理Map中的bean引用
} else {
v = rv;
}
values[i] = v;
}
return values;
}
第二:通过上一步拿到的真实args(实参)就要通过此具体到构造方法
下面我举个简答的Demo来回忆下反射构造函数相关的知识,就是通过确定的实参通过实参的class类型数组作为参数,来获取对应的构造方法(我还没遇到过获取不到的情况),如果获取不到则获取当前BeanClass类的所有构造方法,然后与实参的类型逐个比较,如果不存在则肯定是异常的抛出错误。
package di.demo;
import lombok.Getter;
import lombok.Setter;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Heian
*/
@Setter
@Getter
public class Test {
private String name;
private String height;
List<String> list;
public Test(String name) {
this.name = name;
}
public Test(String name, String height) {
this.name = name;
this.height = height;
}
public Test(String name, String height, ArrayList<String> arrayList) {
this.name = name;
this.height = height;
this.list = arrayList;
}
@Override
public String toString() {
return "test{" +
"name='" + name + '\'' +
", height='" + height + '\'' +
'}';
}
public static void main(String[] args) throws Exception {
String name = "hmm";
String height = "120";
Object[] argsArray = new Object[3];
argsArray[0] = name;
argsArray[1] = height;
argsArray[2] = new ArrayList<>(Arrays.asList("1","2"));
Class<?>[] classes = new Class<?>[3];
for (int i = 0; i < classes.length; i++) {
classes[i] = argsArray[i].getClass();
}
Constructor<Test> constructor = Test.class.getConstructor(classes);
Test test = constructor.newInstance(argsArray);
System.out.println(test.toString());
Constructor ct = null;
Constructor<?>[] constructors = test.getClass().getConstructors();
for (Constructor<?> constructor1 : constructors) {
Class<?>[] parameterTypes = constructor1.getParameterTypes();
if (parameterTypes.length == argsArray.length){
for (int i = 0; i < parameterTypes.length; i++) {
//判断构造函数的形参是否和我们实参数一致
if (!parameterTypes[i].isAssignableFrom(argsArray[i].getClass())){
System.out.println("不一致");
break;
}else {
continue;
}
}
ct = constructor1;
}
}
System.out.println(ct);
System.out.println(ct.equals(constructor));
}
}
所以DefacultBeanFactory定位出一个确切的构造方法是
private Constructor determineConstructor(BeanDefinition bd, Object[] args) throws Exception {
Constructor ct = null;
if(args == null) {return bd.getBeanClass().getConstructor(null);}
Class<?>[] paramType = new Class[args.length];
// 对于原型Bean,从第二次开始获取Bean实例时,可以直接从第一次缓存中获取构造方法
ct = bd.getConstructor();
if(ct != null) {return ct;}
// 根据参数类型获取构造方法
int j = 0;
for(Object p : args) {
paramType[j++] = p.getClass();
}
ct = bd.getBeanClass().getConstructor(paramType);
if(ct == null) {
Constructor<?>[] cts = bd.getBeanClass().getConstructors();
// 判断逻辑:先判断参数数量,依次判断形参跟实参进行类型匹配
outer: for(Constructor<?> c : cts) {
Class<?>[] paramterTypes = c.getParameterTypes();
if(paramterTypes.length == args.length) {
for(int i = 0; i < paramterTypes.length; i++) {
//判断构造函数的形参是否和我们实参数一致
if(!paramterTypes[i].isAssignableFrom(args[i].getClass())) {
continue outer;
}
}
ct = c;
break outer;
}
}
}
if (ct == null){
throw new Exception("找不到对应的构造方法:" + bd);
}
if(bd.isPrototype()) {
bd.setConstructor(ct);
}
return ct;
}
第三:判断出构造方法或工厂方法后,对于原型(多例)Bean,下次获取Bean是否就可以省去判断了?所以需要在BeanDefinition增加缓存对应构造函数的接口
同理,在上一篇文章中说道静态工厂或者普通工厂方法来获取对应的bean也是需要确定唯一的工厂方法,所以同样需要确定唯一的工厂方法,依照上面的方式修改静态工厂方法、工厂方法方式的参数依赖。
private Method determineFactoryMethod(BeanDefinition bd, Object[] args, Class<?> type) throws Exception {
if (type == null) {
type = bd.getBeanClass();
}
String methodName = bd.getFactoryMethodName();
if(args == null) {
return type.getMethod(methodName, null);
}
Method m = null;
// 对于原型bean,从第二次开始获取bean实例时,可直接获得第一次缓存的构造方法。
m = bd.getFactoryMethod();
if (m != null) {
return m;
}
// 根据参数类型获取精确匹配的方法
Class[] paramTypes = new Class[args.length];
int j = 0;
for (Object p : args) {
paramTypes[j++] = p.getClass();
}
try{
m = type.getMethod(methodName, paramTypes);
}catch (NoSuchMethodException e){
// 不做任何处理
m = null;
}
if (m == null) {
// 判断逻辑:先判断参数数量,再依次比对形参类型与实参类型
outer: for (Method m0 : type.getMethods()) {
if (!m0.getName().equals(methodName)) {
continue;
}
Class<?>[] paramterTypes = m0.getParameterTypes();
if (paramterTypes.length == args.length) {
for (int i = 0; i < paramterTypes.length; i++) {
if (!paramterTypes[i].isAssignableFrom(args[i].getClass())) {
continue outer;
}
}
m = m0;
break outer;
}
}
}
if (m == null){
throw new Exception("不存在对应的构造方法!" + bd);
}
// 对于原型bean,可以缓存找到的方法,方便下次构造实例对象。在BeanDefinition中获取设置所用方法的方法。
if (bd.isPrototype()) {
bd.setFactoryMethod(m);
}
return m;
}
第四点:注意循环依赖,比如A类有属性B,B类有属性A,在创建A过程中需要注入B,所以需要创建B,但是创建B类又需要A又会去创建A,如此循环陷入死循环类似于我们的多线程死锁,一般这种情况会造成stackOverFlowError,所以最好实在DefaultFactory中创建线程安全的集合,在doGetBean的方法时将要创建的类放入到集合,创建完成就移除,一旦其他类进来创建发现某个类跟我一样处于创建则抛出异常
private Set<String> buildingBeans = Collections.newSetFromMap(new ConcurrentHashMap());
方法{
// 记录正在创建的Bean
Set<String> ingBeans = this.buildingBeans;
// 检测循环依赖
if(ingBeans.contains(beanName)){
throw new Exception(beanName + " 循环依赖!" + ingBeans);
}
// 记录正在创建的Bean
ingBeans.add(beanName);
......
// 实例创建完成后进行删除
ingBeans.remove(beanName);
}
涉及改动的代码
BeanDefinition
import org.apache.commons.lang.StringUtils;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;
/**
* @author heian
* @date 2021/2/15 2:43 下午
* @description Bean定义接口,告诉工厂如何创建某类bean
*/
public interface BeanDefinition {
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
/**
* 获取bean的类名 构造函数和静态工厂创建对象所需
*/
Class<?> getBeanClass();
void setBeanClass(Class<?> beanClass);
String getScope();
void setScope(String scope);
boolean isSingleton();
boolean isPrototype();
String getFactoryMethodName();//获取个工厂(静态和动态)方法的名字
//成员工厂需要用到,因为通过此name获取factoryBean 来invoke对应bean
void setFactoryMethodName(String factoryMethodName);
String getFactoryBeanName();
void setFactoryBeanName(String factoryBeanName);
default boolean validate(){
//没有对应bean的class信息,意味着只能提供成员工厂构建
if (getBeanClass() == null){
if (StringUtils.isBlank(getFactoryBeanName()) || StringUtils.isBlank(getFactoryMethodName())){
return false;
}
}
//class存在情况,还指定FactoryBeanName构建对象方式冲突
if (getBeanClass() != null && StringUtils.isNotBlank(getFactoryBeanName())){
return false;
}
return true;
}
/**
* 类对,对象交给IOC容器管理,类对象的生命周期还有事情要做
* 1.创建对象后可能需要进行一些初始化
* 2.对象在销毁时肯需要进行一定的特定销毁的逻辑(如资源释放)
* 3.bean定义中提供让用户指定初始化、销毁的方法
* 4.对bean工厂提供getInitMethodName() getDestroyMethodName()
*/
void setInitMethod(String initMethod);
String getInitMethod();
void setDestroyMethod(String destroyMethod);
String getDestroyMethod();
//获取你所需要赋值的成员参数 名称
List<?> getConstructorArgumentValues();
void setConstructorArgumentValues(List<?> constructorArgumentValues);
//获取当前定义bean的构造参数 当实多例bean时,缓存起来省得你通过方法找那个构造函数
Constructor getConstructor();
void setConstructor(Constructor constructor);
Method getFactoryMethod();
void setFactoryMethod(Method factoryMethod);
}
GenericBeanDefinition
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;
/**
* @author heian
* @date 2021/2/15 3:32 下午
* @description 通用的定义注册的实现
*/
public class GenericBeanDefinition implements BeanDefinition{
private Class<?> beanClass;
private String factoryMethodName;//静态或者成员的工厂方法名
private String factoryBeanName;//成员工厂需要用到,因为通过此name获取factoryBean 来invoke对应bean
private String scope = BeanDefinition.SCOPE_SINGLETON;
private String initMethod;
private String destroyMethod;
private List<?> constructorArgumentValues;
private Constructor constructor;//多例bean缓存该构造函数
private Method factoryMethod;
@Override
public Class<?> getBeanClass() {
return this.beanClass;
}
@Override
public void setBeanClass(Class<?> beanClass) {
this.beanClass = beanClass;
}
@Override
public String getScope() {
return this.scope;
}
@Override
public void setScope(String scope) {
this.scope = scope;
}
@Override
public boolean isSingleton() {
return BeanDefinition.SCOPE_SINGLETON.equals(scope);
}
@Override
public boolean isPrototype() {
return BeanDefinition.SCOPE_PROTOTYPE.equals(scope);
}
@Override
public String getFactoryMethodName() {
return this.factoryMethodName;
}
@Override
public void setFactoryMethodName(String factoryMethodName) {
this.factoryMethodName = factoryMethodName;
}
@Override
public String getFactoryBeanName() {
return this.factoryBeanName;
}
@Override
public void setFactoryBeanName(String factoryBeanName) {
this.factoryBeanName = factoryBeanName;
}
@Override
public void setInitMethod(String initMethod) {
this.initMethod = initMethod;
}
@Override
public String getInitMethod() {
return this.initMethod;
}
@Override
public void setDestroyMethod(String destroyMethod) {
this.destroyMethod = destroyMethod;
}
@Override
public String getDestroyMethod() {
return this.destroyMethod;
}
@Override
public List<?> getConstructorArgumentValues() {
return this.constructorArgumentValues;
}
@Override
public void setConstructorArgumentValues(List<?> constructorArgumentValues) {
this.constructorArgumentValues = constructorArgumentValues;
}
@Override
public Constructor getConstructor() {
return this.constructor;
}
@Override
public void setConstructor(Constructor constructor) {
this.constructor = constructor;
}
@Override
public Method getFactoryMethod() {
return this.factoryMethod;
}
@Override
public void setFactoryMethod(Method factoryMethod) {
this.factoryMethod = factoryMethod;
}
}
DefaultBeanFactory
import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author heian
* @date 2021/2/15 3:37 下午
* @description 通过反射机制实现工厂生产实例化bean
*/
public class DefaultBeanFactory implements BeanFactory,BeanDefinitionRegistry, Closeable {
//缓存你要定义的 beanDefinition
private Map<String,BeanDefinition> map = new ConcurrentHashMap<>();
//缓存你要定义的 bean
private Map<String,Object> beanMap = new ConcurrentHashMap<>();
private Set<String> buildingBeans = Collections.newSetFromMap(new ConcurrentHashMap());
@Override
public Object getBean(String beanName) throws Exception{
BeanDefinition bd = map.get(beanName);
Object bean = doGetBean(beanName);
//开始bean的生命周期
if (StringUtils.isNotBlank(bd.getInitMethod())){
Method method = bean.getClass().getMethod(bd.getInitMethod(), null);
method.invoke(bean,null);
}
return bean;
}
protected Object doGetBean(String beanName) throws Exception {
Objects.requireNonNull(beanName,"beanName 不为空");
//先去缓存中判断对象是否已经创建完成
Object bean = beanMap.get(beanName);
if (bean != null){
return bean;
}
//创建对象的方式有三种:构造函数、静态工厂、成员工厂
BeanDefinition beanDefinition = map.get(beanName);
Objects.requireNonNull(beanDefinition,"beanDefinition 不存在");
Class<?> beanClass = beanDefinition.getBeanClass();
// 记录正在创建的Bean
Set<String> ingBeans = this.buildingBeans;
// 检测循环依赖
if(ingBeans.contains(beanName)){
throw new Exception(beanName + " 循环依赖!" + ingBeans);
}
// 记录正在创建的Bean
ingBeans.add(beanName);
if (beanClass != null){
//构造函数
if (StringUtils.isBlank(beanDefinition.getFactoryMethodName())){
bean = createBeanByConstructor(beanDefinition);
}else {
//提供静态工厂创建对象 (知道工厂类名和方法名即可创建对象)
bean = createBeanByStaticFactory(beanDefinition);
}
}else {
//成员工厂构建对象 (不是工厂类 应该是工厂bean名FactoryBean + 工厂方法名)
bean = createBeanByFactoryBean(beanDefinition);
}
// 实例创建完成后进行删除
ingBeans.remove(beanName);
// 对单例bean的处理
if (beanDefinition.isSingleton()){
beanMap.put(beanName,bean);
}
return bean;
}
//通过构造方法产生bean
private Object createBeanByConstructor(BeanDefinition bd) throws Exception {
Object instance = null;
if(CollectionUtils.isEmpty(bd.getConstructorArgumentValues())) {
instance = bd.getBeanClass().newInstance();
}else{
Object[] args = getRealValues(bd.getConstructorArgumentValues());
if(args == null) {
instance = bd.getBeanClass().newInstance();
}else {
return determineConstructor(bd, args).newInstance(args);
}
}
return instance;
}
//通过静态工厂产生bean
private Object createBeanByStaticFactory(BeanDefinition bd) throws Exception {
Object[] realArgs = getRealValues(bd.getConstructorArgumentValues());
Method method = determineFactoryMethod(bd, realArgs,bd.getBeanClass());
Class<?> type = bd.getBeanClass();
return method.invoke(type, realArgs);
}
//通过普通工厂拿到对应的bean
private Object createBeanByFactoryBean(BeanDefinition bd) throws Exception {
String factoryBeanName = bd.getFactoryBeanName();
Object factoryBean = doGetBean(factoryBeanName);//静态工厂产生的FactoryBean
if (factoryBean != null){
Object[] realArgs = getRealValues(bd.getConstructorArgumentValues());
Method method = determineFactoryMethod(bd, realArgs,factoryBean.getClass());
return method.invoke(factoryBean, realArgs);
}
return null;
}
private Method determineFactoryMethod(BeanDefinition bd, Object[] args, Class<?> type) throws Exception {
if (type == null) {
type = bd.getBeanClass();
}
String methodName = bd.getFactoryMethodName();
if(args == null) {
return type.getMethod(methodName, null);
}
Method m = null;
// 对于原型bean,从第二次开始获取bean实例时,可直接获得第一次缓存的构造方法。
m = bd.getFactoryMethod();
if (m != null) {
return m;
}
// 根据参数类型获取精确匹配的方法
Class[] paramTypes = new Class[args.length];
int j = 0;
for (Object p : args) {
paramTypes[j++] = p.getClass();
}
try{
m = type.getMethod(methodName, paramTypes);
}catch (NoSuchMethodException e){
// 不做任何处理
m = null;
}
if (m == null) {
// 判断逻辑:先判断参数数量,再依次比对形参类型与实参类型
outer: for (Method m0 : type.getMethods()) {
if (!m0.getName().equals(methodName)) {
continue;
}
Class<?>[] paramterTypes = m0.getParameterTypes();
if (paramterTypes.length == args.length) {
for (int i = 0; i < paramterTypes.length; i++) {
if (!paramterTypes[i].isAssignableFrom(args[i].getClass())) {
continue outer;
}
}
m = m0;
break outer;
}
}
}
if (m == null){
throw new Exception("不存在对应的构造方法!" + bd);
}
// 对于原型bean,可以缓存找到的方法,方便下次构造实例对象。在BeanDefinition中获取设置所用方法的方法。
if (bd.isPrototype()) {
bd.setFactoryMethod(m);
}
return m;
}
private Constructor determineConstructor(BeanDefinition bd, Object[] args) throws Exception {
Constructor ct = null;
if(args == null) {return bd.getBeanClass().getConstructor(null);}
Class<?>[] paramType = new Class[args.length];
// 对于原型Bean,从第二次开始获取Bean实例时,可以直接从第一次缓存中获取构造方法
ct = bd.getConstructor();
if(ct != null) {return ct;}
// 根据参数类型获取构造方法
int j = 0;
for(Object p : args) {
paramType[j++] = p.getClass();
}
ct = bd.getBeanClass().getConstructor(paramType);
if(ct == null) {
Constructor<?>[] cts = bd.getBeanClass().getConstructors();
// 判断逻辑:先判断参数数量,依次判断形参跟实参进行类型匹配
outer: for(Constructor<?> c : cts) {
Class<?>[] paramterTypes = c.getParameterTypes();
if(paramterTypes.length == args.length) {
for(int i = 0; i < paramterTypes.length; i++) {
//判断构造函数的形参是否和我们实参数一致
if(!paramterTypes[i].isAssignableFrom(args[i].getClass())) {
continue outer;
}
}
ct = c;
break outer;
}
}
}
if (ct == null){
throw new Exception("找不到对应的构造方法:" + bd);
}
if(bd.isPrototype()) {
bd.setConstructor(ct);
}
return ct;
}
/**
* 字段中包含其它引用类型字段:如ioc的bean字段、集合等
*/
private Object[] getRealValues(List<?> args) throws Exception {
if(CollectionUtils.isEmpty(args)) {return null;}
Object[] values = new Object[args.size()];
Object v = null;
for(int i = 0; i < args.size(); i++){
Object rv = args.get(i);
if(rv == null) {
v = null;
}else if (rv instanceof BeanReference){
v = doGetBean(((BeanReference) rv).getBeanName());
}else if (rv instanceof Object[]) {
// TODO 处理集合中的bean引用
} else if (rv instanceof Collection) {
// TODO 处理集合中的bean引用
} else if (rv instanceof Properties) {
// TODO 处理properties中的bean引用
} else if (rv instanceof Map) {
// TODO 处理Map中的bean引用
} else {
v = rv;
}
values[i] = v;
}
return values;
}
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
Objects.requireNonNull(beanName,"注册的bean需要指定 beanName");
Objects.requireNonNull(beanDefinition,"注册的bean需要指定 beanDefinition");
if(!beanDefinition.validate()) {
throw new RuntimeException("名字为["+beanName+"]的bean定义不合法:"+beanDefinition);
}
if(containsBeanDefinition(beanName)) {
throw new RuntimeException("名字为["+beanName+"]已存在:"+getBeanDefinition(beanName));
}
map.put(beanName,beanDefinition);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) {
return this.map.get(beanName);
}
@Override
public boolean containsBeanDefinition(String beanName) {
return map.containsKey(beanName);
}
@Override
public void close() throws IOException {
//针对单例bean进行的销毁方法
map.forEach((s, beanDefinition) -> {
if (beanDefinition.isSingleton() && StringUtils.isNotBlank(beanDefinition.getDestroyMethod())){
try {
Object bean = beanMap.get(s);
if (bean == null){
return;//不会终止循环
}
Method method = bean.getClass().getMethod(beanDefinition.getDestroyMethod(), null);
method.invoke(bean,null);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
});
}
//JVM关闭后会执行所有实现了Closeable接口的方法,也就是我们这个实现的close方法
public void destroy(){
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
//把所有实现closeable接口的参数都加上此代码
try {
close();
} catch (IOException e) {
e.printStackTrace();
}
}));
}
}
测试
测试涉及的类
public interface Gril {
}
public class MagicGril implements Gril {
private String name;
private Boy friend;
public MagicGril(){}
public MagicGril(String name) {
this.name = name;
}
public Boy getFriend() {
return friend;
}
public void setFriend(Boy friend) {
this.friend = friend;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "MagicGril{" +
"name='" + name + '\'' +
'}';
}
}
package di;
public class Lad implements Boy {
private String name;
private Gril friend;
private Money money;
public Lad(String name) {
this.name = name;
}
public Lad(String name, Gril gf) {
this.name = name;
this.friend = gf;
System.out.println("调用了含有Gril参数的构造方法");
}
public Lad(String name, MagicGril gf) {
this.name = name;
this.friend = gf;
System.out.println("调用了含有MagicGril参数的构造方法");
}
public Lad(String name, Money m) {
this.name = name;
this.money = m;
System.out.println("调用了含有Money参数的构造方法");
}
public Gril getFriend() {
return friend;
}
public void setFriend(Gril friend) {
this.friend = friend;
}
@Override
public void sayLove() {
if(friend != null){
System.out.println("I love you, my gril! "+friend);
}else {
System.out.println("I love you, my air! "+hashCode());
}
}
@Override
public void play() {
if(money != null) {
System.out.println("I have money, let's play.");
}else{
System.out.println("I have no money, can't play.");
}
}
public void init() {
System.out.println("我还没谈过恋爱,初始化一个对象吧");
}
public void destroy(){
System.out.println("七夕到底是牵手还是分手?");
}
}
测试方法
package di;
import com.dongnaoedu.network.spring.bean.BeanReference;
import com.dongnaoedu.network.spring.bean.GenericBeanDefinition;
import com.dongnaoedu.network.spring.bean.SingletonBeanPreBuildFactory;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class DItest {
static SingletonBeanPreBuildFactory bf = new SingletonBeanPreBuildFactory();
@Test
public void testConstructorDI() throws Exception {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(Lad.class);
List<Object> args = new ArrayList<>();
args.add("sunwukong");//属性一:名字
args.add(new BeanReference("magicGril"));//属性二:ioc的bean依赖类型
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("swk", bd);
bd = new GenericBeanDefinition();
bd.setBeanClass(MagicGril.class);
args = new ArrayList<>();
args.add("baigujing");//magicGirl的属性一:名字
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("magicGril", bd);
bf.preInstantiateSingletons();
Lad abean = (Lad) bf.getBean("swk");
abean.sayLove();
}
---
调用了含有MagicGril参数的构造方法
preInstantiate: name=swk com.dongnaoedu.network.spring.bean.GenericBeanDefinition@7cef4e59
preInstantiate: name=magicGril com.dongnaoedu.network.spring.bean.GenericBeanDefinition@64b8f8f4
I love you, my gril! MagicGril{name='baigujing'}
}
通过实现属性依赖注入
第一:属性注入和构造方法类似,只不过是通过变量调取某个成员变量的set方法,当然即使类没有set方法也可以通过反射方法file.set(agrs)来实现属性注入,所以我们需要定义PropertyValue类来表明对象的成员变量的字段名和具体的值。
/**
* 属性值类型,用作属性依赖注入
*/
@Data
public class PropertyValue {
private String name;
private Object value;
public PropertyValue(String name, Object value) {
super();
this.name = name;
this.value = value;
}
}
第二:在BeanDefinition中增加获得属性依赖定义的接口,在GenericBeanDefinition中增加对应的实现,因为我们除了上面通过构造方法注入还有就是你的xx成员它用的是属性注入,所以就必须要有此用来实现属性注入
//属性依赖用到
List<PropertyValue> getPropertyValues();
void setPropertyValues(List<PropertyValue> propertyValues);
private List<PropertyValue> propertyValues;
....省略....
@Override
public List<PropertyValue> getPropertyValues() {
return this.propertyValues;
@Override
public void setPropertyValues(List<PropertyValue> propertyValues) {
this.propertyValues = propertyValues;
}
第三:在DefaultBeanFactory中实现属性依赖
private void setPropertyDIValues(BeanDefinition bd, Object instance) throws Exception {
if (CollectionUtils.isEmpty(bd.getPropertyValues())) {
return;
}
for (PropertyValue pv : bd.getPropertyValues()) {
if (StringUtils.isBlank(pv.getName())) {
continue;
}
Class<?> clazz = instance.getClass();
Field p = clazz.getDeclaredField(pv.getName());
p.setAccessible(true);
Object rv = pv.getValue();
Object v = null;
if (rv == null) {
v = null;
} else if (rv instanceof BeanReference) {
v = this.doGetBean(((BeanReference) rv).getBeanName());
} else if (rv instanceof Object[]) {
// TODO 处理集合中的bean引用
} else if (rv instanceof Collection) {
// TODO 处理集合中的bean引用
} else if (rv instanceof Properties) {
// TODO 处理properties中的bean引用
} else if (rv instanceof Map) {
// TODO 处理Map中的bean引用
} else {
v = rv;
}
p.set(instance, v);
}
}
比如我有一个 swk有2个成员变量,一个普通的String name,另一个bgj就是Gril friend,但是这个friend是bean引用类型,但是依赖是通过属性依赖注入的。所以你想制造swk必须先把bgj制造出来,但此时制造的bgj是通过无参构造构造出来的。此时swk就制造完毕了,但是此时你想要进行属性依赖是没法做到的,因为你在定义swk的时候压根就没setPropertyValues(List
package com.dongnaoedu.network.spring.bean;
import java.util.ArrayList;
import java.util.List;
/**
* @author heian
* @date 2021/2/17 11:56 上午
* @description 对于单例bean实行预先加载策略
*/
public class SingletonBeanPreBuildFactory extends DefaultBeanFactory{
//存放那些beanNames
private List<String> beanNames = new ArrayList<>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
super.registerBeanDefinition(beanName, beanDefinition);
synchronized (beanNames){
beanNames.add(beanName);
}
}
public void preInstantiateSingletons() throws Exception {
synchronized (beanNames){
for (String beanName : beanNames) {
BeanDefinition definition = this.getBeanDefinition(beanName);
if (definition.isSingleton()){
//第二次的时候会把bgj进行属性注入
this.getBean(beanName);
System.out.println("preInstantiate: name=" + beanName + " " + definition);
}
}
}
}
}
只有当单例集合便利第二个成员比那辆bgj的时候,因为之前beanMap中这个bgj已经存在于ioc容器中了,就会直接通过dogetBean方法之后调用下面属性注入方法之后才会对它进行一个注入,然后注入bgj有需要swk二swk是直接存放在ioc容器内的(此时swk的bgj属性就已经赋值成功了),最后就ok了。同时证明了一个观点通过成员属性赋值是可以解决循环依赖的。
因为存在一个概念就是此时swk这个类已经诞生了,只不过是其中某个属性bgj并没有完全属性赋值而已。bgj这个类需要依赖swk是没问题的。
测试代码
package di;
import com.dongnaoedu.network.spring.bean.BeanReference;
import com.dongnaoedu.network.spring.bean.GenericBeanDefinition;
import com.dongnaoedu.network.spring.bean.PropertyValue;
import com.dongnaoedu.network.spring.bean.SingletonBeanPreBuildFactory;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class PropertyDItest {
static SingletonBeanPreBuildFactory bf = new SingletonBeanPreBuildFactory();
@Test
public void testPropertyDI() throws Exception {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(Lad.class);
List<Object> args = new ArrayList<>();
args.add("孙悟空");
args.add(new BeanReference("bgj"));
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("swk", bd);
bd = new GenericBeanDefinition();
bd.setBeanClass(MagicGril.class);
List<PropertyValue> propertyValues = new ArrayList<>();
propertyValues.add(new PropertyValue("name", "白骨精"));
propertyValues.add(new PropertyValue("friend", new BeanReference("swk")));
bd.setPropertyValues(propertyValues);
bf.registerBeanDefinition("bgj", bd);
bf.preInstantiateSingletons();
MagicGril g = (MagicGril) bf.getBean("bgj");
System.out.println(g.getName() + " " + g.getFriend());
g.getFriend().sayLove();
}
}
代码地址:https://github.com/jkhumm/network-study/tree/master/src/main/java/com/dongnaoedu/network/spring/bean