SpringIOC

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;
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值