极客时间:小马哥学习笔记
IoC主要实现策略:面试官总问IoC和DI的区别,他真的理解吗?
Ioc的主要实现策略
- 服务定位模式。通常是通过JNDI这种技术获取JavaEE的组件
- 依赖注入
- 上下文依赖查询
- 模板方法
- 策略模式(不太深入)
可以说就是依赖查找和依赖注入
IoC容器的职责:IoC除了依赖注入,还涵盖哪些职责呢?
- 实现与执行任务之间的解耦
- 关注设计上的最终目标,而不是它具体的实现
- 释放这个模块
- 模块取消,(比如依赖变更了,如果是同步调用,影响比较明显,但是用IOC的话,可能影响不是很明显)
白话文职责
- 通用职责
- 依赖处理
- 依赖查找
- 依赖注入 - 生命周期管理
- 容器
- 托管的资源(Java Beans 或其他资源) - 配置
- 容器
- 外部化配置
- 托管的资源
IoC容器的实现
传统IoC容器实现:JavaBeans也是IoC容器吗?
传统JavaBeans实现
贫血模型、只有可写方法、可读方法、默认构造参数
public class Person {
/**
* 年龄
*/
private Integer age;
/**
* 名字
*/
private String name;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
获取JavaBeans元信息
public class BeanInfoDemo {
public static void main(String[] args) throws IntrospectionException {
//Java自省的方式来操作
BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);
Stream.of(beanInfo.getPropertyDescriptors())
.forEach(propertyDescriptor -> {
System.out.println(propertyDescriptor.toString());
});
}
}
结果
java.beans.PropertyDescriptor[name=age; propertyType=class java.lang.Integer; readMethod=public java.lang.Integer ioc.eg1.Person.getAge(); writeMethod=public void ioc.eg1.Person.setAge(java.lang.Integer)]
java.beans.PropertyDescriptor[name=class; propertyType=class java.lang.Class; readMethod=public final native java.lang.Class java.lang.Object.getClass()]
java.beans.PropertyDescriptor[name=name; propertyType=class java.lang.String; readMethod=public java.lang.String ioc.eg1.Person.getName(); writeMethod=public void ioc.eg1.Person.setName(java.lang.String)]
为什么会 获取这些信息?
先来看看BeanInfo源码里面有什么
public interface BeanInfo {
//Bean的描述信息
BeanDescriptor getBeanDescriptor();
//Bean事件的描述信息
EventSetDescriptor[] getEventSetDescriptors();
//Bean的字段信息
PropertyDescriptor[] getPropertyDescriptors();
这里我们获取了Person的字段元信息,但是为什么多了一个class字段呢?
因为每个Object都有一个可读方法getClass(),然后就会把它当成一个默认属性,误以为是一个property
所以上面就会多出来一个属性class,并且他只有一个读方法
想要关掉它,就多传一个参数
BeanInfo beanInfo = Introspector.getBeanInfo(Person.class,Object.class);
这个第二个参数就是父类,防止多层次的类都打印出来,这个参数就是stopClass
那我们的类型转换元信息转换怎么做的
public class BeanInfoDemo {
public static void main(String[] args) throws IntrospectionException {
//Java自省的方式来操作
BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);
Stream.of(beanInfo.getPropertyDescriptors())
.forEach(propertyDescriptor -> {
//PropetyDescriptor允许添加属性编辑器 - PropertyEditor
//我们以往的GUI程序都会 text(String) --> PropertyType
//Spring怎么做类型转换的
//Person name -> String
// age ->Integer
Class<?> propertyType = propertyDescriptor.getPropertyType();
String propertyName = propertyDescriptor.getName();
if("age".equals(propertyName)){
//为"age" 字段/属性增加 PropertyEditor
//输入一个String类型,输出一个Integer类型
//其实很简单就是Integer.valueOf();
//具体怎么操作
//1.写自己的PropertyEditor的实现
//2.关联起来
//3.将我们的Bean放进去,创建出来
propertyDescriptor.setPropertyEditorClass(StringToIntegerPropertyEditor.class);
propertyDescriptor.createPropertyEditor(Person.class);
}
});
}
static class StringToIntegerPropertyEditor extends PropertyEditorSupport {
//方法拦截
@Override
public void setAsText(String text){
Integer value = Integer.valueOf(text);
setValue(value);
}
}
}
PropertyEditorSupport
public class PropertyEditorSupport implements PropertyEditor {
public void setValue(Object value) {
this.value = value;
firePropertyChange();
}
/**
* Gets the value of the property.
*
* @return The value of the property.
*/
public Object getValue() {
return value;
}
public String getAsText() {
return (this.value != null)
? this.value.toString()
: null;
}
/**
* Sets the property value by parsing a given String. May raise
* java.lang.IllegalArgumentException if either the String is
* badly formatted or if this kind of property can't be expressed
* as text.
*
* @param text The string to be parsed.
*/
public void setAsText(String text) throws java.lang.IllegalArgumentException {
if (value instanceof String) {
setValue(text);
return;
}
throw new java.lang.IllegalArgumentException(text);
}
我理解的就是Spring再做一个Bean的元信息、类型转换的时候,接收进来的都是String,然后在其他实现类里重写这个方法,将它转换成我们Bean定义的Type,就像上面的String—>Integer方法一样
Spring3.0以前,大量的类型转换实践都是基于PropertyEditorSupport来做的,上面的几个操作,基本满足于我们的元数据或元信息编程,他也就是一些类型配置和转换的一些根据