设计简单的springIOC案例
一、文档介绍
1. 模块依赖
要做好相关准备工作之前,首先要定义好各模块,说的通俗一点,主要有下面4个模块构成:
1.定义bean相关的pojo类
PropertyValue类:
PropertyValue
通俗来讲是单个bean
下的单个property
标签,存放该标签中的属性值,例如下图中PropertyValue
存放了property
标签中的各属性值(name
、ref
或者value
)
<bean id="userDao" class="com.zhkucst.dao.impl.UserDaoImpl"></bean>
<bean id="userService" class="com.zhkucst.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
MutablePropertyValues类:
MutablePropertyValues
通俗来讲就是所有property
标签,即可以说是PropertyValue
的一个集合列表List
,实现了Iterable
接口,可以使用该接口下的一些实现子类的方法,从而便于对所有PropertyValue
的遍历和其他CRUD
操作
BeanDefinition类:
BeanDefinition
通俗来讲是一个bean
标签,当中包含了id属性、name
属性和标签下的property
标签,所以MutablePropertyValues
作为了它的成员变量
2.定义注册表相关类
注册表相关类的实现很简单,由一个接口和它的实现类就可以了
BeanDefinitionRegistry接口:
BeanDefinitionRegistry
主要是对上边的BeanDefinition
类的存放和获取,即作为了BeanDefinition
的一个容器
SimpleBeanDefinitionRegistry类:
SimpleBeanDefinitionRegistry
是对BeanDefinitionRegistry
接口方法的实现,用它来存放BeanDefinition
,用的是哈希表HashMap
来存放,方法的实现就是对哈希表的操作
3.定义解析器相关类
解析器的实现也非常简单,一个读取配置文件和获取注册表的接口,和一个实现该接口的子实现类
BeanDefinitionReader接口:
BeanDefinitionReader
接口主要向外提供读取配置文件和获取注册表的方法
XmlBeanDefinitionReade实现类:
BeanDefinitionReader
是用来读取配置文件,将读取到的数据封装给上面的注册表,注册表存放的数据是所有的bean
对象,可以通俗地说,bean
的pojo
类就是一个数据,而注册表registry
就是一个存放数据的仓库,而解析器就是一个将数据拿到仓库的工具,涉及到数据怎么拿?怎么放到仓库?所以每一个解析器都有自己独特的获取数据和存放数据的方式
4.定义IOC容器相关类
顶层接口是BeanFactory
,子接口是ApplicationContext
,抽象类是AbstractApplicationContext
,具体实现子类是AbstractApplicationContext
BeanFactory接口:
提供获取bean
对象的两种抽象方法
ApplicationContext子接口:
继承顶级接口,提供加载配置文件和初始化容器的抽象方法
AbstractApplicationContext抽象实现类:
调用BeanDefinitionReader
接口加载bean
配置文件和获取注册表的方法,对加载配置文件和初始化容器方法的简单封装,不去实例化bean
对象,只调用了抽象方法,加载后bean
对象会存放到注册表中
ClassPathXmlApplicationContext继承类:
做完初始化操作,即注册表中有了bean
对象的数据后,实现BeanDefinitionReader
父类中调用抽象实例化bean对象的方法
2. 各模块详细uml图
1.bean相关的pojo类
2.注册表相关类
3.解析器相关类
4.IOC容器相关类
二、代码演示
工程目录:
其中在实例化中需要将获取到的实例名拼接为具体的方法名,从而通过setter调用实现自动实例化bean对象,这里把代码封装到utils包下的StringUtils类中
package com.itheima.framework.utils;
/**
* @version v1.0
* @ClassName: StringUtils
* @Description: TODO
* @Author: fyp
* @data: 2021年 09月 30日 12:26
*/
public class StringUtils {
private StringUtils() {
}
public static String getSetterMethodByFieldName(String fieldName) {
String methodName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
return methodName;
}
}
1.bean相关的pojo类
propertyValue类:
package com.itheima.framework.beans;
/**
* @version v1.0
* @ClassName: PropertyValue
* @Description: 用来封装bean标签下的property标签的属性
* name属性
* ref属性
* value属性:给基本数据类型及String类型数据赋的值
* @Author: fyp
* @data: 2021年 09月 28日 23:29
*/
public class PropertyValue {
private String name;
private String ref;
private String value;
public PropertyValue(String name, String ref, String value) {
this.name = name;
this.ref = ref;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRef() {
return ref;
}
public void setRef(String ref) {
this.ref = ref;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
MutablePropertyValues类:
package com.itheima.framework.beans;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @version v1.0
* @ClassName: MutablePropertyValues
* @Description: 用来存储和管理多个对象
* @Author: fyp
* @data: 2021年 09月 28日 23:35
*/
public class MutablePropertyValues implements Iterable<PropertyValue> {
private final List<PropertyValue> propertyValueList;
public MutablePropertyValues() {
this.propertyValueList = new ArrayList<PropertyValue>();
}
public MutablePropertyValues(List<PropertyValue> propertyValueList) {
if(propertyValueList == null){
this.propertyValueList = new ArrayList<PropertyValue>();
}else{
this.propertyValueList = propertyValueList;
}
}
public PropertyValue[] getPropertyValues(){
return propertyValueList.toArray(new PropertyValue[0]);
}
public PropertyValue getPropertyValue(String propertyName){
for (PropertyValue propertyValue : propertyValueList) {
if(propertyValue.getName().equals(propertyName)){
return propertyValue;
}
}
return null;
}
public boolean isEmpty(){
return propertyValueList.isEmpty();
}
public MutablePropertyValues addPropertyValue(PropertyValue pv){
for (int i = 0; i < propertyValueList.size(); i++) {
PropertyValue currentPv = propertyValueList.get(i);
if(currentPv.getName().equals(pv.getName())){
propertyValueList.set(i,pv);
return this;//实现链式编程
}
}
this.propertyValueList.add(pv);
return this;//实现链式编程
}
public boolean contains(String propertyName){
return getPropertyValue(propertyName) != null;
}
public Iterator<PropertyValue> iterator(){
return propertyValueList.iterator();
}
}
BeanDefinition类:
package com.itheima.framework.beans;
/**
* @version v1.0
* @ClassName: BeanDefinition
* @Description: 用来封装bean标签数据
* id属性
* class属性
* property子标签的数据
* @Author: fyp
* @data: 2021年 09月 29日 20:16
*/
public class BeanDefinition {
private String id;
private String className;
private MutablePropertyValues propertyValues;
public BeanDefinition() {
this.propertyValues = new MutablePropertyValues();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public MutablePropertyValues getPropertyValues() {
return propertyValues;
}
public void setPropertyValues(MutablePropertyValues propertyValues) {
this.propertyValues = propertyValues;
}
}
2.注册表相关类
BeanDefinitionRegistry接口:
package com.itheima.framework.beans.factory.support;
import com.itheima.framework.beans.BeanDefinition;
/**
* @version v1.0
* @ClassName: BeanDefinitionRegistry
* @Description: 注册表对象
* @Author: fyp
* @data: 2021年 09月 29日 21:21
*/
public interface BeanDefinitionRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
void removeBeanDefinition(String beanName) throws Exception;
BeanDefinition getBeanDefinition(String beanName) throws Exception;
boolean containsBeanDefinition(String beanName);
int getBeanDefinitionCount();
String[] getBeanDefinitionNames();
}
SimpleBeanDefinitionRegistry实现类:
package com.itheima.framework.beans.factory.support;
import com.itheima.framework.beans.BeanDefinition;
import java.util.HashMap;
import java.util.Map;
/**
* @version v1.0
* @ClassName: SimpleBeanDefinitionRegistry
* @Description: TODO
* @Author: fyp
* @data: 2021年 09月 29日 21:24
*/
public class SimpleBeanDefinitionRegistry implements BeanDefinitionRegistry{
private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<String, BeanDefinition>();
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
beanDefinitionMap.put(beanName, beanDefinition);
}
public void removeBeanDefinition(String beanName) throws Exception {
beanDefinitionMap.remove(beanName);
}
public BeanDefinition getBeanDefinition(String beanName) throws Exception {
return beanDefinitionMap.get(beanName);
}
public boolean containsBeanDefinition(String beanName) {
return beanDefinitionMap.containsKey(beanName);
}
public int getBeanDefinitionCount() {
return beanDefinitionMap.size();
}
public String[] getBeanDefinitionNames() {
return beanDefinitionMap.keySet().toArray(new String[0]);
}
}
3.解析器相关类
BeanDefinitionReader接口:
package com.itheima.framework.beans.factory.support;
/**
* @version v1.0
* @ClassName: BeanDefinitionReader
* @Description: 用来解析配置文件的,而该接口只是定义了规范
* @Author: fyp
* @data: 2021年 09月 29日 21:46
*/
public interface BeanDefinitionReader {
BeanDefinitionRegistry getRegistry();
void loadBeanDefinitions(String configLocation) throws Exception;
}
XmlBeanDefinitionReader实现类:
package com.itheima.framework.beans.factory.xml;
import com.itheima.framework.beans.BeanDefinition;
import com.itheima.framework.beans.PropertyValue;
import com.itheima.framework.beans.factory.support.BeanDefinitionReader;
import com.itheima.framework.beans.factory.support.BeanDefinitionRegistry;
import com.itheima.framework.beans.factory.support.SimpleBeanDefinitionRegistry;
import com.itheima.framework.beans.MutablePropertyValues;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.List;
/**
* @version v1.0
* @ClassName: XmlBeanDefinitionReader
* @Description: 针对xml配置文件进行解析的类
* @Author: fyp
* @data: 2021年 09月 29日 21:48
*/
public class XmlBeanDefinitionReader implements BeanDefinitionReader {
private BeanDefinitionRegistry registry;
public XmlBeanDefinitionReader() {
this.registry = new SimpleBeanDefinitionRegistry();
}
public BeanDefinitionRegistry getRegistry() {
return registry;
}
public void loadBeanDefinitions(String configLocation) throws Exception {
SAXReader reader = new SAXReader();
InputStream is = XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(configLocation);
Document document = reader.read(is);
Element rootElement = document.getRootElement();
List<Element> beanElements = rootElement.elements("bean");
for (Element beanElement : beanElements) {
String id = beanElement.attributeValue("id");
String className = beanElement.attributeValue("class");
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setId(id);
beanDefinition.setClassName(className);
MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
List<Element> propertyElements = beanElement.elements("property");
for (Element propertyElement : propertyElements) {
String name = propertyElement.attributeValue("name");
String ref = propertyElement.attributeValue("ref");
String value = propertyElement.attributeValue("value");
PropertyValue propertyValue = new PropertyValue(name, ref, value);
mutablePropertyValues.addPropertyValue(propertyValue);
}
beanDefinition.setPropertyValues(mutablePropertyValues);
registry.registerBeanDefinition(id, beanDefinition);
}
}
}
4.IOC容器相关类
BeanFactory接口:
package com.itheima.framework.beans.factory;
/**
* @version v1.0
* @ClassName: BeanFactory
* @Description: IOC容器父接口
* @Author: fyp
* @data: 2021年 09月 29日 22:24
*/
public interface BeanFactory {
Object getBean(String name) throws Exception;
<T> T getBean(String name, Class<? extends T> clazz) throws Exception;
}
ApplicationContext子接口:
package com.itheima.framework.context;
import com.itheima.framework.beans.factory.BeanFactory;
/**
* @version v1.0
* @ClassName: ApplicationContext
* @Description: 定义非延时加载功能
* @Author: fyp
* @data: 2021年 09月 29日 22:34
*/
public interface ApplicationContext extends BeanFactory {
void refresh() throws Exception;
}
AbstractApplicationContext抽象实现类:
package com.itheima.framework.context.support;
import com.itheima.framework.beans.factory.support.BeanDefinitionReader;
import com.itheima.framework.beans.factory.support.BeanDefinitionRegistry;
import com.itheima.framework.context.ApplicationContext;
import java.util.HashMap;
import java.util.Map;
/**
* @version v1.0
* @ClassName: AbstractApplicationContext
* @Description: ApplicationContext接口的子实现类,用于立即加载
* @Author: fyp
* @data: 2021年 09月 30日 11:54
*/
public abstract class AbstractApplicationContext implements ApplicationContext {
protected BeanDefinitionReader beanDefinitionReader;
protected Map<String, Object> singletonObjects = new HashMap<String, Object>();
protected String configLocation;
public void refresh() throws Exception {
beanDefinitionReader.loadBeanDefinitions(configLocation);
finishBeInitialization();
}
private void finishBeInitialization() throws Exception {
BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
String[] beanNames = registry.getBeanDefinitionNames();
for (String beanName : beanNames) {
getBean(beanName);
}
}
}
ClassPathXmlApplicationContext继承类:
package com.itheima.framework.context.support;
import com.itheima.framework.beans.BeanDefinition;
import com.itheima.framework.beans.MutablePropertyValues;
import com.itheima.framework.beans.PropertyValue;
import com.itheima.framework.beans.factory.support.BeanDefinitionRegistry;
import com.itheima.framework.beans.factory.xml.XmlBeanDefinitionReader;
import com.itheima.framework.utils.StringUtils;
import java.lang.reflect.Method;
/**
* @version v1.0
* @ClassName: ClassPathXmlApplicationContext
* @Description: IOC容器具体的子实现类
* 用于加载类路径下的xml格式的配置文件
* @Author: fyp
* @data: 2021年 09月 30日 12:06
*/
public class ClassPathXmlApplicationContext extends AbstractApplicationContext{
public ClassPathXmlApplicationContext(String configLocation) {
this.configLocation = configLocation;
beanDefinitionReader = new XmlBeanDefinitionReader();
try {
this.refresh();
}catch (Exception e) {
}
}
public Object getBean(String name) throws Exception {
Object obj = singletonObjects.get(name);
if(obj != null) {
return obj;
}
BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
BeanDefinition beanDefinition = registry.getBeanDefinition(name);
String className = beanDefinition.getClassName();
Class<?> clazz = Class.forName(className);
Object beanObj = clazz.newInstance();
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues) {
String propertyName = propertyValue.getName();
String value = propertyValue.getValue();
String ref = propertyValue.getRef();
if(ref != null && !"".equals(ref)){
Object bean = getBean(ref);
String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if(methodName.equals(method.getName())){
method.invoke(beanObj, bean);//beanObj:调用的该底层方法的对象,bean:调用该方法的参数
}
}
}
if(value != null && !"".equals(value)){
String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
Method method = clazz.getMethod(methodName, String.class);
method.invoke(beanObj, value);
}
}
singletonObjects.put(name, beanObj);
return beanObj;
}
public <T> T getBean(String name, Class<? extends T> clazz) throws Exception {
Object bean = getBean(name);
if(bean == null) {
return null;
}
return clazz.cast(bean);
}
}
就这些吧
算了算了,再写个实例给大家验证下吧
controller代码:
package com.zhkucst.controller;
import com.itheima.framework.context.ApplicationContext;
import com.itheima.framework.context.support.ClassPathXmlApplicationContext;
import com.zhkucst.service.UserService;
/**
* @version v1.0
* @ClassName: UserController
* @Description: TODO
* @Author: fyp
* @data: 2021年 09月 23日 22:08
*/
public class UserController {
public static void main(String[] args) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
//UserService userService = xmlBeanFactory.getBean("userService", UserService.class);
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.add();
}
}
Userdao代码:
package com.zhkucst.dao.impl;
import com.zhkucst.dao.UserDao;
/**
* @version v1.0
* @ClassName: UserDaoImpl
* @Description: TODO
* @Author: fyp
* @data: 2021年 09月 23日 21:59
*/
public class UserDaoImpl implements UserDao {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public UserDaoImpl(){
System.out.println("userDao被创建了");
}
@Override
public void add() {
System.out.println("UserDao:" + username + "==" + password);
}
}
UserService代码:
package com.zhkucst.service.impl;
import com.zhkucst.dao.UserDao;
import com.zhkucst.service.UserService;
import sun.security.util.Password;
/**
* @version v1.0
* @ClassName: UserServiceImpl
* @Description: TODO
* @Author: fyp
* @data: 2021年 09月 23日 21:59
*/
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserServiceImpl() {
System.out.println("userService被创建了");
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void add() {
System.out.println("UserService...");
userDao.add();
}
}
配置文件applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!--spring配置文件: 声明service, dao, 工具类等对象-->
<bean id="userDao" class="com.zhkucst.dao.impl.UserDaoImpl">
<property name="username" value="zs"></property>
<property name="password" value="123456"></property>
</bean>
<bean id="userService" class="com.zhkucst.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
</beans>
结果:
最后说明:
本文是对B站博主黑马程序员的设计模式中案例的使用,并且对其做了总结,链接:https://www.bilibili.com/video/BV1Np4y1z7BU?p=154
以及自己对案例的看法和解释
如有冒犯,请联系作者