DI(Dependency injection)依赖注入
哪些地方会有依赖?
构造参数依赖
属性依赖
依赖注入的本质是什么?
给值:给入构造参数值,给属性赋值
参数值、属性值可能是什么值?
直接值、bean依赖
直接值会有哪几种情形?
基本数据类型值、String
数组、集合
Properties
Map
本质:参数值、属性值都是值。Bean工厂在进行依赖注入时,就是给入值
把值给到bean工厂,bean工厂就可以帮住赋值了。
如何告诉bean工厂该给如什么构造参数值?即如何来定义参数依赖?
如何来定义属性依赖?
DI依赖注入-构造参数依赖定义分析
如何定义构造参数依赖?
假如
public class Girl{
public Girl(String name,int age,char cup,Boy boyfriend){
...
}
...
}
要创建一个Girl是如何创建的?直接给入就行了
Boy tom = new Boy("Tom");
Girl beautGirl = new Girl("小丽",18,'D',tom );
怎么定义构造参数依赖?
第一个参数值是:“小丽”
第一个参数值是:18
第一个参数值是:‘D’
第一个参数值是:依赖一个Boy bean
参数可以多个,用什么存储?
集合:List
参数有顺序,如何体现顺序?
按照参数顺序放入List
参数值可以是直接值,也可以是bean依赖,如何表示?
Object
如果用Object来表示值,如何区分是Bean依赖?
为Bean依赖定义一种数据类型(BeanReference),bean工厂在构造Bean实例的时候,
遍历判断参数是否是BeanReference,如果是则替换为依赖的Bean实例
如果直接值是数组、集合等,它们的元素中有的是Bean依赖,怎么处理?
元素值还是用BeanReference,同样bean工厂在使用时需遍历替换
BeanReference该是怎样的?
BeanReference就是用来说明bean依赖的:依赖哪个bean
DI的实现:
在BeanDefinition中增加构造参数值的接口
在GenericBeanDefinition中增加对应这个方法的实现:
DI实现:BeanFactory中实现构造参数依赖注入1:
首先需要把bean定义中的构造参数引用转为真实的值,在DefaultBeanFactory中增加一个方法:
DI实现:BeanFactory中实现构造参数依赖注入2:
有参数了,如何断定是哪个构造方法、哪个工厂方法?
判断的逻辑:先根据参数的类型进行精确匹配查找,如果未找到则进行2
获得所有的构造方法,遍历,通过参数数量过滤,再对比形参类型与实参类型
1、方法是可以重载的
2、形参定义的时候可能是接口或者父类,实参则是具体的子实现
3、反射提供的获取的构造方法、方法的API如下:
当判断出构造方法或工厂方法后,对于原型Bean,下次获取Bean的时候可以缓存下这个构造方法或工厂方法,在BeanDefinition中增加缓存的方法:
在GenericBeanDefinition中增加对应的实现:
接下来就可以写构造方法或工厂方法的代码了
BeanDefinition的接口比上次多了几个方法:
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;
public interface BeanDefinition {
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
/**
* 类
*/
Class<?> getBeanClass();
/**
* Scope
*/
String getScope();
/**
* 是否单例
*/
boolean isSingleton();
/**
* 是否原型
*/
boolean isPrototype();
/**
* 工厂bean名
*/
String getFactoryBeanName();
/**
* 工厂方法名
*/
String getFactoryMethodName();
/**
* 初始化方法
*/
String getInitMethodName();
/**
* 销毁方法
*/
String getDestroyMethodName();
/* 下面的四个方法是供beanFactory中使用的 */
public Constructor<?> getConstructor();
public void setConstructor(Constructor<?> constructor);
public Method getFactoryMethod();
public void setFactoryMethod(Method factoryMethod);
/**
* 校验bean定义的合法性
*/
default boolean validate() {
// 没定义class,工厂bean或工厂方法没指定,则不合法。
if (this.getBeanClass() == null) {
if (StringUtils.isBlank(getFactoryBeanName()) || StringUtils.isBlank(getFactoryMethodName())) {
return false;
}
}
// 定义了类,又定义工厂bean,不合法
if (this.getBeanClass() != null && StringUtils.isNotBlank(getFactoryBeanName())) {
return false;
}
return true;
}
/**
* 获得构造参数定义 <br>
*/
List<?> getConstructorArgumentValues();
/**
* 属性依赖<br>
* @return
*/
List<PropertyValue> getPropertyValues();
}
public class PropertyValue {
private String name;
private Object value;
public PropertyValue(String name, Object value) {
super();
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
GenericBeanDefinition是BeanDefinition的实现类,看一下这个实现类代码:
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;
public class GenericBeanDefinition implements BeanDefinition {
private Class<?> beanClass;
private String scope = BeanDefinition.SCOPE_SINGLETON;
private String factoryBeanName;
private String factoryMethodName;
private String initMethodName;
private String destroyMethodName;
private Constructor<?> constructor;
private Method factoryMethod;
private List<?> constructorArgumentValues;
private List<PropertyValue> propertyValues;
public void setBeanClass(Class<?> beanClass) {
this.beanClass = beanClass;
}
public void setScope(String scope) {
if (StringUtils.isNotBlank(scope)) {
this.scope = scope;
}
}
public void setFactoryBeanName(String factoryBeanName) {
this.factoryBeanName = factoryBeanName;
}
public void setFactoryMethodName(String factoryMethodName) {
this.factoryMethodName = factoryMethodName;
}
public void setInitMethodName(String initMethodName) {
this.initMethodName = initMethodName;
}
public void setDestroyMethodName(String destroyMethodName) {
this.destroyMethodName = destroyMethodName;
}
@Override
public Class<?> getBeanClass() {
return this.beanClass;
}
@Override
public String getScope() {
return this.scope;
}
@Override
public boolean isSingleton() {
return BeanDefinition.SCOPE_SINGLETON.equals(this.scope);
}
@Override
public boolean isPrototype() {
return BeanDefinition.SCOPE_PROTOTYPE.equals(this.scope);
}
@Override
public String getFactoryBeanName() {
return this.factoryBeanName;
}
@Override
public String getFactoryMethodName() {
return this.factoryMethodName;
}
@Override
public String getInitMethodName() {
return this.initMethodName;
}
@Override
public String getDestroyMethodName() {
return this.destroyMethodName;
}
public List<?> getConstructorArgumentValues() {
return constructorArgumentValues;
}
public void setConstructorArgumentValues(List<?> constructorArgumentValues) {
this.constructorArgumentValues = constructorArgumentValues;
}
public List<PropertyValue> getPropertyValues() {
return propertyValues;
}
public void setPropertyValues(List<PropertyValue> propertyValues) {
this.propertyValues = propertyValues;
}
public Constructor<?> getConstructor() {
return constructor;
}
public void setConstructor(Constructor<?> constructor) {
this.constructor = constructor;
}
public Method getFactoryMethod() {
return factoryMethod;
}
public void setFactoryMethod(Method factoryMethod) {
this.factoryMethod = factoryMethod;
}
@Override
public String toString() {
return "GenericBeanDefinition [beanClass=" + beanClass + ", scope=" + scope + ", factoryBeanName="
+ factoryBeanName + ", factoryMethodName=" + factoryMethodName + ", initMethodName=" + initMethodName
+ ", destroyMethodName=" + destroyMethodName + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((beanClass == null) ? 0 : beanClass.hashCode());
result = prime * result + ((destroyMethodName == null) ? 0 : destroyMethodName.hashCode());
result = prime * result + ((factoryBeanName == null) ? 0 : factoryBeanName.hashCode());
result = prime * result + ((factoryMethodName == null) ? 0 : factoryMethodName.hashCode());
result = prime * result + ((initMethodName == null) ? 0 : initMethodName.hashCode());
result = prime * result + ((scope == null) ? 0 : scope.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
GenericBeanDefinition other = (GenericBeanDefinition) obj;
if (beanClass == null) {
if (other.beanClass != null)
return false;
} else if (!beanClass.equals(other.beanClass))
return false;
if (destroyMethodName == null) {
if (other.destroyMethodName != null)
return false;
} else if (!destroyMethodName.equals(other.destroyMethodName))
return false;
if (factoryBeanName == null) {
if (other.factoryBeanName != null)
return false;
} else if (!factoryBeanName.equals(other.factoryBeanName))
return false;
if (factoryMethodName == null) {
if (other.factoryMethodName != null)
return false;
} else if (!factoryMethodName.equals(other.factoryMethodName))
return false;
if (initMethodName == null) {
if (other.initMethodName != null)
return false;
} else if (!initMethodName.equals(other.initMethodName))
return false;
if (scope == null) {
if (other.scope != null)
return false;
} else if (!scope.equals(other.scope))
return false;
return true;
}
}
在DefaultBeanFactory中增加查找构造方法的方法:
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class DefaultBeanFactory implements BeanFactory, BeanDefinitionRegistry, Closeable {
private final Log logger = LogFactory.getLog(getClass());
private Map<String, BeanDefinition> beanDefintionMap = new ConcurrentHashMap<>(256);
private Map<String, Object> beanMap = new ConcurrentHashMap<>(256);
private ThreadLocal<Set<String>> buildingBeans = new ThreadLocal<>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionRegistException {
Objects.requireNonNull(beanName, "注册bean需要给入beanName");
Objects.requireNonNull(beanDefinition, "注册bean需要给入beanDefinition");
// 校验给入的bean是否合法
if (!beanDefinition.validate()) {
throw new BeanDefinitionRegistException("名字为[" + beanName + "] 的bean定义不合法:" + beanDefinition);
}
if (this.containsBeanDefinition(beanName)) {
throw new BeanDefinitionRegistException(
"名字为[" + beanName + "] 的bean定义已存在:" + this.getBeanDefinition(beanName));
}
this.beanDefintionMap.put(beanName, beanDefinition);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) {
return this.beanDefintionMap.get(beanName);
}
@Override
public boolean containsBeanDefinition(String beanName) {
return this.beanDefintionMap.containsKey(beanName);
}
@Override
public Object getBean(String name) throws Exception {
return this.doGetBean(name);
}
protected Object doGetBean(String beanName) throws Exception {
Objects.requireNonNull(beanName, "beanName不能为空");
Object instance = beanMap.get(beanName);
if (instance != null) {
return instance;
}
BeanDefinition bd = this.getBeanDefinition(beanName);
Objects.requireNonNull(bd, "不存在name为:" + beanName + "beean 定义!");
// 记录正在创建的Bean
Set<String> ingBeans = this.buildingBeans.get();
if (ingBeans == null) {
ingBeans = new HashSet<>();
this.buildingBeans.set(ingBeans);
}
// 检测循环依赖
if (ingBeans.contains(beanName)) {
throw new Exception(beanName + " 循环依赖!" + ingBeans);
}
// 记录正在创建的Bean
ingBeans.add(beanName);
Class<?> type = bd.getBeanClass();
if (type != null) {
if (StringUtils.isBlank(bd.getFactoryMethodName())) {
// 构造方法来构造对象
instance = this.createInstanceByConstructor(bd);
} else {
// 静态工厂方法
instance = this.createInstanceByStaticFactoryMethod(bd);
}
} else {
// 工厂bean方式来构造对象
instance = this.createInstanceByFactoryBean(bd);
}
// 创建好实例后,移除创建中记录
ingBeans.remove(beanName);
// 给入属性依赖
this.setPropertyDIValues(bd, instance);
// 执行初始化方法
this.doInit(bd, instance);
if (bd.isSingleton()) {
beanMap.put(beanName, instance);
}
return instance;
}
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);
}
}
// 构造方法来构造对象
private Object createInstanceByConstructor(BeanDefinition bd) throws Exception {
try {
Object[] args = this.getConstructorArgumentValues(bd);
if (args == null) {
return bd.getBeanClass().newInstance();
} else {
// 决定构造方法
return this.determineConstructor(bd, args).newInstance(args);
}
} catch (SecurityException e1) {
logger.error("创建bean的实例异常,beanDefinition:" + bd, e1);
throw e1;
}
}
private Object[] getConstructorArgumentValues(BeanDefinition bd) throws Exception {
return this.getRealValues(bd.getConstructorArgumentValues());
}
private Object[] getRealValues(List<?> defs) throws Exception {
if (CollectionUtils.isEmpty(defs)) {
return null;
}
Object[] values = new Object[defs.size()];
int i = 0;
Object v = null;
for (Object rv : defs) {
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;
}
values[i++] = v;
}
return values;
}
private Constructor<?> determineConstructor(BeanDefinition bd, Object[] args) throws Exception {
Constructor<?> ct = null;
if (args == null) {
return bd.getBeanClass().getConstructor(null);
}
// 对于原型bean,从第二次开始获取bean实例时,可直接获得第一次缓存的构造方法。
ct = bd.getConstructor();
if (ct != null) {
return ct;
}
// 根据参数类型获取精确匹配的构造方法
Class<?>[] paramTypes = new Class[args.length];
int j = 0;
for (Object p : args) {
paramTypes[j++] = p.getClass();
}
try {
ct = bd.getBeanClass().getConstructor(paramTypes);
} catch (Exception e) {
// 这个异常不需要处理
}
if (ct == null) {
// 没有精确参数类型匹配的,则遍历匹配所有的构造方法
// 判断逻辑:先判断参数数量,再依次比对形参类型与实参类型
outer: for (Constructor<?> ct0 : bd.getBeanClass().getConstructors()) {
Class<?>[] paramterTypes = ct0.getParameterTypes();
if (paramterTypes.length == args.length) {
for (int i = 0; i < paramterTypes.length; i++) {
if (!paramterTypes[i].isAssignableFrom(args[i].getClass())) {
continue outer;
}
}
ct = ct0;
break outer;
}
}
}
if (ct != null) {
// 对于原型bean,可以缓存找到的构造方法,方便下次构造实例对象。在BeanDefinfition中获取设置所用构造方法的方法。
// 同时在上面增加从beanDefinition中获取的逻辑。
if (bd.isPrototype()) {
bd.setConstructor(ct);
}
return ct;
} else {
throw new Exception("不存在对应的构造方法!" + bd);
}
}
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 (Exception e) {
// 这个异常不需要处理
}
if (m == null) {
// 没有精确参数类型匹配的,则遍历匹配所有的方法
// 判断逻辑:先判断参数数量,再依次比对形参类型与实参类型
outer: for (Method m0 : type.getMethods()) {
if (!m0.getName().equals(methodName)) {
continue;
}
Class<?>[] paramterTypes = m.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) {
// 对于原型bean,可以缓存找到的方法,方便下次构造实例对象。在BeanDefinfition中获取设置所用方法的方法。
// 同时在上面增加从beanDefinition中获取的逻辑。
if (bd.isPrototype()) {
bd.setFactoryMethod(m);
}
return m;
} else {
throw new Exception("不存在对应的构造方法!" + bd);
}
}
// 静态工厂方法
private Object createInstanceByStaticFactoryMethod(BeanDefinition bd) throws Exception {
Class<?> type = bd.getBeanClass();
Object[] realArgs = this.getRealValues(bd.getConstructorArgumentValues());
Method m = this.determineFactoryMethod(bd, realArgs, null);
return m.invoke(type, realArgs);
}
// 工厂bean方式来构造对象
private Object createInstanceByFactoryBean(BeanDefinition bd) throws Exception {
Object factoryBean = this.doGetBean(bd.getFactoryBeanName());
Object[] realArgs = this.getRealValues(bd.getConstructorArgumentValues());
Method m = this.determineFactoryMethod(bd, realArgs, factoryBean.getClass());
return m.invoke(factoryBean, realArgs);
}
/**
* 执行初始化方法
*
* @param bd
* @param instance
* @throws Exception
*/
private void doInit(BeanDefinition bd, Object instance) throws Exception {
// 执行初始化方法
if (StringUtils.isNotBlank(bd.getInitMethodName())) {
Method m = instance.getClass().getMethod(bd.getInitMethodName(), null);
m.invoke(instance, null);
}
}
@Override
public void close() throws IOException {
// 执行单例实例的销毁方法
for (Entry<String, BeanDefinition> e : this.beanDefintionMap.entrySet()) {
String beanName = e.getKey();
BeanDefinition bd = e.getValue();
if (bd.isSingleton() && StringUtils.isNotBlank(bd.getDestroyMethodName())) {
Object instance = this.beanMap.get(beanName);
try {
Method m = instance.getClass().getMethod(bd.getDestroyMethodName(), null);
m.invoke(instance, null);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e1) {
logger.error("执行bean[" + beanName + "] " + bd + " 的 销毁方法异常!", e1);
}
}
}
}
}
BeanReference:
public class BeanReference {
private String beanName;
public BeanReference(String beanName) {
super();
this.beanName = beanName;
}
/**
* 获得引用的beanName
*
* @return
*/
public String getBeanName() {
return this.beanName;
}
}
PreBuildBeanFactory:
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class PreBuildBeanFactory extends DefaultBeanFactory {
private final Log logger = LogFactory.getLog(getClass());
private List<String> beanNames = new ArrayList<>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionRegistException {
super.registerBeanDefinition(beanName, beanDefinition);
synchronized (beanNames) {
beanNames.add(beanName);
}
}
public void preInstantiateSingletons() throws Exception {
synchronized (beanNames) {
for (String name : beanNames) {
BeanDefinition bd = this.getBeanDefinition(name);
if (bd.isSingleton()) {
this.doGetBean(name);
if (logger.isDebugEnabled()) {
logger.debug("preInstantiate: name=" + name + " " + bd);
}
}
}
}
}
}
PropertyValue:
public class PropertyValue {
private String name;
private Object value;
public PropertyValue(String name, Object value) {
super();
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
剩下的其他的类都不变,话说依赖注入代码挺烦的。而且不debug根本看不懂。
我回头在后续文章放上代码的连接,大家有兴趣去看一下。我就不贴代码了。