1.构造参数依赖,上一篇中的几种构建对象都不涉及传入参数的问题
2.属性依赖,构建出来的对象属性会存在依赖
复制代码
赋值,给入构造参数值,还有对属性的赋值
复制代码
直接赋予的值和bean依赖(使用另外的bean)
复制代码
1.基本数据类型,String
2.数组,集合
3.Properties
4.map
5.对象
复制代码
public class Girl {
public Girl(String name,int age,char cup,Boy boyfriend){}
}
复制代码
Boy Mike = new Boy();
Girl beauty = new Girl("WT",24,'A',Mike);
这种时候直接赋值,很是简单
复制代码
1.第一个参数值"WT"
2.第二个参数值"24"
3.第三个参数值是'A'
4.第四个参数值是一个Boy的bean
复制代码
集合或者数组
复制代码
按参数顺序放入List便可
复制代码
只能使用Object类型:List<Object> constructorArgumentValues
复制代码
此时咱们须要为bean依赖定义一个数据类型BeanReference,
bean工厂在构造bean实例时须要进行遍历参数是否为
BeanReference类型,若是是,替换成依赖的bean实例
复制代码
元素值仍是使用BeanReference,
bean工厂在使用时应该遍历此数组/集合,存在即替换
复制代码
/**
* 用于依赖注入中描述bean依赖
*/
public class BeanReference {
private String beanName;
public BeanReference(String beanName){
super();
this.beanName = beanName;
}
/**
* 得到引用的beanName
* @return
*/
public String getBeanName(){
return this.beanName;
}
}
复制代码
BeanDefinition---List<?> getConstructorArgumentValues();
复制代码
private List<?> constructorArgumentValues;
复制代码
private Object[] getConstructorArgumentValues(BeanDefinition beanDefinition) throws Exception{
return this.getRealValues(beanDefinition.getConstructorArgumentValues());
}
复制代码
private Object[] getRealValues(List<?> defs) throws Exception{
if (CollectionUtils.isEmpty(defs)){return null;}
Object[] values = new Object[defs.size()];
int i = 0;
//values数组的元素
Object value = null;
for (Object realValue : defs){
if (realValue == null){
value = null;
}else if (realValue instanceof BeanReference){
value = this.doGetBean(((BeanReference) realValue).getBeanName());
···
}else {value = realValue;}
values[i++] = value;
}
return values;
}
复制代码
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
复制代码
1.方法是能够重载的(参数数量和参数类型的判断)
2.形参定义时多是接口或者父类,实参是具体的子实现
3.反射提供的获取的构造方法,方法的API(如下的Class指的都是**参数**的类型)
(getConstrutors()和getConstructor(Class<?>...))
(getMethods()和getMethod(String,Class<?>...))
复制代码
1.先根据参数的类型进行精确匹配查找,若是没有找到,则进行第二步查找
2.获取全部的构造方法遍历,经过参数数量过滤,再比对形参类型和实参类型
(为何第一步没法找到,也就是上面说起到的 “形参定义时多是接口或者父类,实参是具体的子实现” 这个缘由)
复制代码
对于prototype,咱们能够缓存这个构造方法或工厂方法
咱们在BeanDefinition中增长缓存的方法
//如下4个方法仅供BeanFactory使用
public Constructor<?> getConstructor();
public void setConstructor(Constructor<?> constructor);
public Method getFactoryMethod();
public void setFactoryMethod(Method method);
复制代码
private Constructor<?> constructor;
private Method factoryMethod;
@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 method) {
this.factoryMethod = factoryMethod;
}
复制代码
private Constructor determineConstructor(BeanDefinition beanDefinition,Object[] args) throws Exception{
Constructor constructor = null;
//当没有任何一个参数时直接获取无参构造方法
if (args == null){
return beanDefinition.getBeanClass().getConstructor(null);
}
//对于原型bean,第二次开始获取Bean实例时,可直接获取第一次缓存的构造方法
constructor = beanDefinition.getConstructor();
if (constructor != null){
return constructor;
}
//根据参数类型获取精确匹配的构造方法
Class<?>[] paramTypes = new Class[args.length];
int j = 0;
for (Object paramType : args){
paramTypes[j++] = paramType.getClass();
}
try {
constructor = beanDefinition.getConstructor();
}catch (Exception e){
//此异常不须要进行处理
}
if (constructor == null){
//把全部的构造器所有遍历出来一一比对
Outer: for (Constructor<?> allConstructor : beanDefinition.getBeanClass().getConstructors()){
Class<?>[] pTypes = allConstructor.getParameterTypes();
//此构造方法的参数长度等于提供参数长度
if (pTypes.length == args.length){
for (int i = 0;i<pTypes.length;i++){
//若是第一个参数的类型就已经不匹配了,就直接再也不继续比对了,直接跳转到外循环
if (!pTypes[i].isAssignableFrom(args[i].getClass())){
continue Outer;
}
}
//若是以上皆匹配的话,就直接获取到这个构造器,而后直接让循环终止
constructor = allConstructor;
break Outer;
}
}
}
if (constructor != null){
if (beanDefinition.isPrototype()){
//对原型bean构造器进行缓存方便下次查找
beanDefinition.setConstructor(constructor);
}
return constructor;
}else {
throw new Exception("不存在对应的构造方法!"+beanDefinition);
}
}
复制代码
private Object createInstanceByConstructor(BeanDefinition beanDefinition) throws IllegalAccessException, InstantiationException {
try{
return beanDefinition.getBeanClass().newInstance();
} catch (SecurityException e){
logger.error("建立bean的实例异常,beanDefinition"+beanDefinition,e);
throw e;
}
}
复制代码
private Object createInstanceByConstructor(BeanDefinition beanDefinition) throws Exception {
try {
//获取真正的参数值
Object[] args = this.getConstructorArgumentValues(beanDefinition);
if (args == null) {
return beanDefinition.getBeanClass().newInstance();
} else {
// 决定构造方法
return this.determineConstructor(beanDefinition, args).newInstance(args);
}
} catch (SecurityException e1) {
logger.error("建立bean的实例异常,beanDefinition:" + beanDefinition, e1);
throw e1;
}
}
复制代码
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中获取设置所用方法的方法。
if (bd.isPrototype()) {
bd.setFactoryMethod(m);
}
return m;
} else {
throw new Exception("不存在对应的构造方法!" + bd);
}
}
复制代码
private Object createInstanceByStaticFactoryMethod(BeanDefinition beanDefinition) throws Exception{
Class<?> type = beanDefinition.getBeanClass();
Method method = type.getMethod(beanDefinition.getFactoryMethodName(),null);
return method.invoke(type,null);
}
复制代码
private Object createInstanceByStaticFactoryMethod(BeanDefinition beanDefinition) throws Exception{
Class<?> type = beanDefinition.getBeanClass();
Object[] realArgs = this.getRealValues(beanDefinition.getConstructorArgumentValues());
Method m = this.determineFactoryMethod(beanDefinition, realArgs, null);
return m.invoke(type, realArgs);
}
复制代码
private Object createInstanceByFactoryBean(BeanDefinition beanDefinition) throws Exception{
Object factoryBean = this.doGetBean(beanDefinition.getFactoryBeanName());
Method method = factoryBean.getClass().getMethod(beanDefinition.getFactoryMethodName(),null);
return method.invoke(factoryBean,null);
}
复制代码
private Object createInstanceByFactoryBean(BeanDefinition beanDefinition) throws Exception{
Object factoryBean = this.doGetBean(beanDefinition.getFactoryBeanName());
Object[] realArgs = this.getRealValues(beanDefinition.getConstructorArgumentValues());
Method m = this.determineFactoryMethod(beanDefinition, realArgs, factoryBean.getClass());
return m.invoke(factoryBean, realArgs);
}
复制代码
1.构造对象时能够循环依赖吗?
A:不能够在构造实例对象时的循环依赖
2.如何发现循环依赖?
A:加入一个正在构造的bean的记录,每一个bean开始构造时加入到记录中,构造完成就移走,
若是有依赖,先看依赖的bean是否在构造中,若是是,就构成了循环,抛出异常
复制代码
DefaultBeanFactory.java---添加一个字段:
private ThreadLocal<Set<String>> buildingBeans = new ThreadLocal<>();
放进ThreadLocal的一个集合,是为了线程安全
复制代码
// 记录正在建立的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);
复制代码
// 建立好实例后,移除建立中记录
ingBeans.remove(beanName);
复制代码
某个属性依赖某个值
复制代码
属性名,值,定义一个类,表示这俩个值
复制代码
List
复制代码
同样
复制代码
import lombok.Data;
@Data
public class PropertyValue {
private String name;
private Object value;
}
复制代码
List<PropertyValue> getPropertyValues();
复制代码
private List<PropertyValue> propertyValues;
public List<PropertyValue> getPropertyValues() {
return propertyValues;
}
public void setPropertyValues(List<PropertyValue> propertyValues) {
this.propertyValues = propertyValues;
}
复制代码
// 建立好实例后,移除建立中记录
ingBeans.remove(beanName);
// 给入属性依赖
this.setPropertyDIValues(bd, instance);
// 执行初始化方法
this.doInit(bd, 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);
}
}
复制代码
package MySpring.DITestUtils;
public class ABean {
private String name;
private CBean cb;
public ABean(String name, CBean cb) {
super();
this.name = name;
this.cb = cb;
System.out.println("调用了含有CBean参数的构造方法");
}
public ABean(String name, CCBean cb) {
super();
this.name = name;
this.cb = cb;
System.out.println("调用了含有CCBean参数的构造方法");
}
public ABean(CBean cb) {
super();
this.cb = cb;
}
public void doSomthing() {
System.out.println(System.currentTimeMillis() + " " + this.name + " cb.name=" + this.cb.getName());
}
public void init() {
System.out.println("ABean.init() 执行了");
}
public void destroy() {
System.out.println("ABean.destroy() 执行了");
}
}
复制代码
public class ABeanFactory {
public static ABean getABean(String name, CBean cb) {
return new ABean(name, cb);
}
public ABean getABean2(String name, CBean cb) {
return new ABean(name, cb);
}
}
复制代码
public class CBean {
private String name;
public CBean(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
复制代码
}java
public class CCBean extends CBean {
public CCBean(String name) {
super(name);
}
复制代码
}apache
public class DBean {
private EBean ebean;
public DBean(EBean ebean) {
super();
this.ebean = ebean;
}
复制代码
}数组
public class EBean {
private DBean dbean;
public EBean(DBean dbean) {
super();
this.dbean = dbean;
}
复制代码
}缓存
@Data
public class FBean {
private String name;
private int age;
private ABean aBean;
复制代码
}安全
public class DITest {
static PreBuildBeanFactory bf = new PreBuildBeanFactory();
@Test
public void testConstructorDI() throws Exception {
GeneralBeanDefinition bd = new GeneralBeanDefinition();
bd.setBeanClass(ABean.class);
List<Object> args = new ArrayList<>();
args.add("abean");
args.add(new BeanReference("cbean"));
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("abean", bd);
bd = new GeneralBeanDefinition();
bd.setBeanClass(CBean.class);
args = new ArrayList<>();
args.add("cbean");
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("cbean", bd);
bf.preInstantiateSingletons();
ABean abean = (ABean) bf.getBean("abean");
abean.doSomthing();
}
@Test
public void testStaticFactoryMethodDI() throws Exception {
GeneralBeanDefinition bd = new GeneralBeanDefinition();
bd.setBeanClass(ABeanFactory.class);
bd.setFactoryMethodName("getABean");
List<Object> args = new ArrayList<>();
args.add("abean02");
args.add(new BeanReference("cbean02"));
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("abean02", bd);
bd = new GeneralBeanDefinition();
bd.setBeanClass(CBean.class);
args = new ArrayList<>();
args.add("cbean02");
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("cbean02", bd);
bf.preInstantiateSingletons();
ABean abean = (ABean) bf.getBean("abean02");
abean.doSomthing();
}
@Test
public void testFactoryMethodDI() throws Exception {
GeneralBeanDefinition bd = new GeneralBeanDefinition();
bd.setFactoryBeanName("abeanFactory");
bd.setFactoryMethodName("getABean2");
List<Object> args = new ArrayList<>();
args.add("abean03");
args.add(new BeanReference("cbean02"));
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("abean03", bd);
bd = new GeneralBeanDefinition();
bd.setBeanClass(ABeanFactory.class);
bf.registerBeanDefinition("abeanFactory", bd);
bf.preInstantiateSingletons();
ABean abean = (ABean) bf.getBean("abean03");
abean.doSomthing();
}
@Test
public void testChildTypeDI() throws Exception {
GeneralBeanDefinition bd = new GeneralBeanDefinition();
bd.setBeanClass(ABean.class);
List<Object> args = new ArrayList<>();
args.add("abean04");
args.add(new BeanReference("ccbean01"));
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("abean04", bd);
bd = new GeneralBeanDefinition();
bd.setBeanClass(CCBean.class);
args = new ArrayList<>();
args.add("Ccbean01");
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("ccbean01", bd);
bf.preInstantiateSingletons();
ABean abean = (ABean) bf.getBean("abean04");
abean.doSomthing();
}
}
复制代码
调用了含有CCBean参数的构造方法
1555720164146 abean04 cb.name=Ccbean01
调用了含有CBean参数的构造方法
1555720164162 abean cb.name=cbean
调用了含有CBean参数的构造方法
1555720164162 abean02 cb.name=cbean02
调用了含有CBean参数的构造方法
1555720164162 abean03 cb.name=cbean02
复制代码
java.lang.Exception: dbean 循环依赖![ebean, dbean]
复制代码
调用了含有CBean参数的构造方法
FFBean01 18
1555720275503 abean01 cb.name=cbean01
复制代码