IoC:控制反转,指的是创建Bean实例的角色发生了反转,由程序员主动new变为框架为你new,它离不开DI
DI:依赖注入,就是设置成员变量。
看一一个例子
public interface UserDao {
List<User> queryUserList(Map<String, Object> param);
}
public class UserDaoImpl implements UserDao {
// 数据源对象
private DataSource dataSource;
// setter方法注入DataSource
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
// 初始化方法
public void init() {
System.out.println("初始化方法被调用");
}
@Override
public List<User> queryUserList(Map<String, Object> param) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet rs = null;
try {
// 通过数据源获取连接
connection = dataSource.getConnection();
// 定义sql语句 ?表示占位符
String sql = "select * from user where username = ?";
// 获取预处理 statement
preparedStatement = connection.prepareStatement(sql);
// 设置参数,第一个参数为 sql 语句中参数的序号(从 1 开始),第二个参数为设置的
preparedStatement.setObject(1, param.get("username"));
// 向数据库发出 sql 执行查询,查询出结果集
rs = preparedStatement.executeQuery();
// 遍历查询结果集
List<User> results = new ArrayList<User>();
User result = null;
Class<?> clazz = User.class;
while (rs.next()) {
// 遍历一行数据,则创建一个User对象
result = (User) clazz.newInstance();
// 获取结果集的元数据
ResultSetMetaData metaData = rs.getMetaData();
// 获取每一行包含的列的数量
int columnCount = metaData.getColumnCount();
// 遍历所有列
for (int i = 0; i < columnCount; i++) {
// 获取每一列的名称
String columnName = metaData.getColumnName(i + 1);
// 通过反射获取指定属性名称的Field对象(保证列名和属性名一致)
Field field = clazz.getDeclaredField(columnName);
// 设置暴力破解
field.setAccessible(true);
// 给私有属性赋值
field.set(result, rs.getObject(i + 1));
}
results.add(result);
}
return results;
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放资源
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
}
}
}
return null;
}
}
A同学根本不想关心UserServiceImpl对象是怎么new的,他只是想测试查询功能。
IoC要做的事情,就是让使用对象的同学只需要找工厂去要对应的对象即可,不需要自己创建。
IoC是将创建对象的权利,由程序员这边,反转给spring容器去创建
@Test
public void test(){
// A 程序员他其实只想使用业务对象去调用对应的服务
// 但是现在A程序员还需要去进行业务对象的构建
// A程序员也不了解业务对象的构造细节
// 理解IoC
UserServiceImpl userService = new UserServiceImpl();
UserDaoImpl userDao = new UserDaoImpl();
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/zhicui?characterEncoding=utf-8");
dataSource.setUsername("root");
dataSource.setPassword("root");
userDao.setDataSource(dataSource);
userService.setUserDao(userDao);
//实现用户查询功能
Map<String, Object> map = new HashMap<>();
map.put("username","左护法");
List<User> users = userService.queryUsers(map);
System.out.println(users);
}
使用面向过程思维和配置文件的方式去实现容器化管理Bean
/**
* 使用面向过程思维和配置文件的方式去实现容器化管理Bean
*/
public class Test {
// 存储单例Bean实例的Map容器
private Map<String,Object> singletonObjects = new HashMap<>();
// 存储BeanDefinition的容器
private Map<String, BeanDefinition> beanDefinitions = new HashMap<>();
@Before
public void beforse(){
// TODO XML解析
//完成XML解析,其实就是完成BeanDefinition的注册
// XML解析,解析的结果,放入beanDefinitions中
String location = "beans.xml";
// 获取流对象
InputStream inputStream = getInputStream(location);
// 创建文档对象
Document document = createDocument(inputStream);
// 按照spring定义的标签语义去解析Document文档
registerBeanDefinitions(document.getRootElement());
}
// 由A程序员编写
@Test
public void test(){
// A 程序员他其实只想使用业务对象去调用对应的服务
// B 程序员编写了一段代码给A程序员提供对象
// UserService userService = getUserService();
UserService userService = (UserService) getBean("userService");
//实现用户查询功能
Map<String, Object> map = new HashMap<>();
map.put("username","千年老亚瑟");
List<User> users = userService.queryUsers(map);
System.out.println(users);
}
// B程序员
public UserService getUserService(){
UserServiceImpl userService = new UserServiceImpl();
UserDaoImpl userDao = new UserDaoImpl();
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost/zhicui?characterEncoding=utf-8");
dataSource.setUsername("root");
dataSource.setPassword("root");
userDao.setDataSource(dataSource);
userService.setUserDao(userDao);
return userService;
}
// D程序员
// 解决的是扩展性问题:通过配置的方式去解决扩展性问题
// 使用XML配置文件进行Bean的创建
// 1.管理要new出来的bean的class信息(要new几个对象,就需要配置几个class信息)
// <bean id="bean的唯一name" class="要new的对象的全路径"></bean>
// 2.管理要new出来的bean的属性的依赖关系(如果A对象依赖了B对象,那么这两个对象都要配置class信息,并且要确定关系)
// <bean id="bean的唯一name" class="要new的对象的全路径">
// <property name="属性名称" ref="要建立关系的另一个bean的唯一name"/>
// </bean>
// 3.读取静态的信息,去创建对象
// BeanDefinition类--->用来存储<bean>标签中的信息
// Map<String,BeanDefinition>
// 4.利用反射从BeanDefinition中获取class信息,区创建对象
public Object getBean(String beanName){
// 1.首先从singletonObjects集合中获取对应beanName的实例
Object singletonObject = this.singletonObjects.get(beanName);
// 2.如果有对象,则直接返回
if (singletonObject != null){
return singletonObject;
}
// 3.如果没有改对象,则获取对应的BeanDefinition信息
BeanDefinition beanDefinition = this.beanDefinitions.get(beanName);
// 4.判断是单例还是多例,如果是单例,则走单例创建Bean流程
// String scope = beanDefinition.getScope();
// if ("singleton".equals(scope)){
//
// }else if ("prototype".equals(scope)){
//
// }
if (beanDefinition.isSingleton()){
singletonObject = doCreateBean(beanDefinition) ;
this.singletonObjects.put(beanName,singletonObject);
}else if(beanDefinition.isPrototype()){
singletonObject = doCreateBean(beanDefinition) ;
}
// 5.单例流程中,需要将创建出来的Bean放入singletonObjects集合中
// 6.如果是多例,走多例的创建Bean流程
return singletonObject;
}
private Object doCreateBean(BeanDefinition beanDefinition) {
// 1.Bean的实例化
Object bean = createBeanByConstructor(beanDefinition);
// 2.Bean的属性填充(依赖注入)
populateBean(bean,beanDefinition);
// 3.Bean的初始化
initilizeBean(bean,beanDefinition);
return bean;
}
private void initilizeBean(Object bean, BeanDefinition beanDefinition) {
// TODO 需要针对Aware接口标记的类进行特殊处理
// TODO 可以进行IntilizingBean接口的处理
invokeInitMethod(bean,beanDefinition);
}
private void invokeInitMethod(Object bean, BeanDefinition beanDefinition) {
try {
String initMethod = beanDefinition.getInitMethod();
if (initMethod == null) {
return;
}
Class<?> clazzType = beanDefinition.getClazzType();
Method method = clazzType.getDeclaredMethod(initMethod);
method.setAccessible(true);
method.invoke(bean);
}catch (Exception e){
e.printStackTrace();
}
}
private void populateBean(Object bean, BeanDefinition beanDefinition) {
List<PropertyValue> propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue pv : propertyValues) {
String name = pv.getName();
// 这不是我们需要给Bean设置的value值
Object value = pv.getValue();
Object valueToUse = resoleValue(value);
setProperty(bean,name,valueToUse);
}
}
private void setProperty(Object bean,String name,Object valueToUse){
try {
Class<?> aClass = bean.getClass();
Field field = aClass.getDeclaredField(name);
field.setAccessible(true);
field.set(bean,valueToUse);
}catch (Exception e){
e.printStackTrace();
}
}
private Object resoleValue(Object value) {
if (value instanceof TypedStringValue){
TypedStringValue typedStringValue = (TypedStringValue) value;
Class<?> targetType = typedStringValue.getTargetType();
String stringValue = typedStringValue.getValue();
if (targetType == Integer.class){
return Integer.parseInt(stringValue);
}else if (targetType == String.class){
return stringValue;
}//TODO 其他类型
}else if (value instanceof RuntimeBeanReference){
RuntimeBeanReference beanReference = (RuntimeBeanReference) value;
String ref = beanReference.getRef();
// 递归调用
return getBean(ref);
}
return null;
}
private Object createBeanByConstructor(BeanDefinition beanDefinition) {
// TODO 静态工厂方法、工厂实例方法
// 构造器方式去创建Bean实例
try {
Class<?> clazzType = beanDefinition.getClazzType();
// 选择无参构造器
Constructor<?> constructor = clazzType.getDeclaredConstructor();
return constructor.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void registerBeanDefinitions(Element rootElement) {
// 获取<bean>和自定义标签(比如mvc:interceptors)
List<Element> elements = rootElement.elements();
for (Element element : elements) {
// 获取标签名称
String name = element.getName();
if (name.equals("bean")) {
// 解析默认标签,其实也就是bean标签
parseDefaultElement(element);
} else {
// 解析自定义标签,比如aop:aspect标签
parseCustomElement(element);
}
}
}
@SuppressWarnings("unchecked")
private void parseDefaultElement(Element beanElement) {
try {
if (beanElement == null) {
return;
}
// 获取id属性
String id = beanElement.attributeValue("id");
// 获取name属性
String name = beanElement.attributeValue("name");
// 获取class属性
String clazzName = beanElement.attributeValue("class");
if (clazzName == null || "".equals(clazzName)) {
return;
}
// 获取init-method属性
String initMethod = beanElement.attributeValue("init-method");
// 获取scope属性
String scope = beanElement.attributeValue("scope");
scope = scope != null && !scope.equals("") ? scope : "singleton";
// 获取beanName
String beanName = id == null ? name : id;
Class<?> clazzType = Class.forName(clazzName);
beanName = beanName == null ? clazzType.getSimpleName() : beanName;
// 创建BeanDefinition对象
// 此次可以使用构建者模式进行优化
BeanDefinition beanDefinition = new BeanDefinition(clazzName, beanName);
beanDefinition.setInitMethod(initMethod);
beanDefinition.setScope(scope);
// 获取property子标签集合
List<Element> propertyElements = beanElement.elements();
for (Element propertyElement : propertyElements) {
parsePropertyElement(beanDefinition, propertyElement);
}
// 注册BeanDefinition信息
this.beanDefinitions.put(beanName, beanDefinition);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private void parsePropertyElement(BeanDefinition beanDefination, Element propertyElement) {
if (propertyElement == null)
return;
// 获取name属性
String name = propertyElement.attributeValue("name");
// 获取value属性
String value = propertyElement.attributeValue("value");
// 获取ref属性
String ref = propertyElement.attributeValue("ref");
// 如果value和ref都有值,则返回
if (value != null && !value.equals("") && ref != null && !ref.equals("")) {
return;
}
/**
* PropertyValue就封装着一个property标签的信息
*/
PropertyValue pv = null;
if (value != null && !value.equals("")) {
// 因为spring配置文件中的value是String类型,而对象中的属性值是各种各样的,所以需要存储类型
TypedStringValue typeStringValue = new TypedStringValue(value);
Class<?> targetType = getTypeByFieldName(beanDefination.getClazzName(), name);
typeStringValue.setTargetType(targetType);
pv = new PropertyValue(name, typeStringValue);
beanDefination.addPropertyValue(pv);
} else if (ref != null && !ref.equals("")) {
RuntimeBeanReference reference = new RuntimeBeanReference(ref);
pv = new PropertyValue(name, reference);
beanDefination.addPropertyValue(pv);
} else {
return;
}
}
private Class<?> getTypeByFieldName(String beanClassName, String name) {
try {
Class<?> clazz = Class.forName(beanClassName);
Field field = clazz.getDeclaredField(name);
return field.getType();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void parseCustomElement(Element element) {
// AOP、TX、MVC标签的解析,都是走该流程
}
private InputStream getInputStream(String location) {
return this.getClass().getClassLoader().getResourceAsStream(location);
}
private Document createDocument(InputStream inputStream) {
Document document = null;
try {
SAXReader reader = new SAXReader();
document = reader.read(inputStream);
return document;
} catch (DocumentException e) {
e.printStackTrace();
}
return null;
}
}
BeanDefinition对象
public class BeanDefinition {
// bean标签的class属性
private String clazzName;
// bean标签的class属性对应的Class对象
private Class<?> clazzType;
// bean标签的id属性和name属性都会存储到该属性值,id和name属性是二选一使用的
private String beanName;
// 初始化方法名称
private String initMethod;
// 该信息是默认的配置,如果不配置就默认是singleton
private String scope;
/**
* bean中的属性信息
*/
private List<PropertyValue> propertyValues = new ArrayList<>();
private static final String SCOPE_SINGLETON = "singleton";
private static final String SCOPE_PROTOTYPE = "prototype";
public BeanDefinition(String clazzName, String beanName) {
this.beanName = beanName;
this.clazzName = clazzName;
this.clazzType = resolveClassName(clazzName);
}
private Class<?> resolveClassName(String clazzName) {
try {
return Class.forName(clazzName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public String getInitMethod() {
return initMethod;
}
public void setInitMethod(String initMethod) {
this.initMethod = initMethod;
}
public List<PropertyValue> getPropertyValues() {
return propertyValues;
}
public void addPropertyValue(PropertyValue propertyValue) {
this.propertyValues.add(propertyValue);
}
public String getClazzName() {
return clazzName;
}
public void setClazzName(String clazzName) {
this.clazzName = clazzName;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public void setPropertyValues(List<PropertyValue> propertyValues) {
this.propertyValues = propertyValues;
}
public Class<?> getClazzType() {
return clazzType;
}
public boolean isSingleton() {
return SCOPE_SINGLETON.equals(this.scope);
}
public boolean isPrototype() {
return SCOPE_PROTOTYPE.equals(this.scope);
}
}
beans.xml
<beans>
<bean id="userService"
class="com.zhicui.spring.service.UserServiceImpl">
<!-- 引用类型 -->
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 该类有一个初始化方法 -->
<bean id="userDao" class="com.zhicui.spring.dao.UserDaoImpl"
init-method="init">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 该类有一个初始化方法 -->
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" scope="singleton" >
<property name="driverClassName"
value="com.mysql.jdbc.Driver"></property>
<property name="url"
value="jdbc:mysql://localhost:3306/zhicui?characterEncoding=utf-8"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
</beans>
User对象
@Data
public class User {
private int id;
private String username;
private Date birthday;
private String sex;
private String address;
}
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;
}
}
public class RuntimeBeanReference {
// ref的属性值
private String ref;
public String getRef() {
return ref;
}
public void setRef(String ref) {
this.ref = ref;
}
public RuntimeBeanReference(String ref) {
super();
this.ref = ref;
}
}
public class TypedStringValue {
// value属性值
private String value;
// value属性值对应的真正类型(Bean中属性的类型)
private Class<?> targetType;
public TypedStringValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Class<?> getTargetType() {
return targetType;
}
public void setTargetType(Class<?> targetType) {
this.targetType = targetType;
}
}