网站建设 实训,新手如何做网站,网站建设方案目录,闲鱼钓鱼网站怎么做继续整理记录这段时间来的收获#xff0c;详细代码可在我的Gitee仓库Java设计模式克隆下载学习使用#xff01;
7.4 自定义Spring IOC
创建新模块#xff0c;结构如图![[Pasted image 20230210173222.png]]
7.4.1 定义bean相关POJO类
7.4.1.1 定义propertyValue类
/** …继续整理记录这段时间来的收获详细代码可在我的Gitee仓库Java设计模式克隆下载学习使用
7.4 自定义Spring IOC
创建新模块结构如图![[Pasted image 20230210173222.png]]
7.4.1 定义bean相关POJO类
7.4.1.1 定义propertyValue类
/** * AuthorPhil * ClassName: PropertyValue * Description: * 用来封装bean标签下的property标签属性 * name属性 * ref属性 * value属性给基本数据类型及String类型赋值 * Date 2023/2/8 21:45 * Version: 1.0 **/public class propertyValue { private String name; private String ref; private String value; public propertyValue() { } 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; }
}7.4.1.2 定义MultiplePropertyValue类
一个bean 标签可以有多个property子标签故用multiplePropertyValue类来存储PropertyValue对象
public class MultiplePropertyValues implements IterablePropertyValue{
// 定义list集合对象用来存储PropertyValue对象 private final ListPropertyValue propertyValueList; public MultiplePropertyValues() { this.propertyValueList new ArrayListPropertyValue (); } public MultiplePropertyValues(ListPropertyValue propertyValueList) { if(propertyValueList null) this.propertyValueList new ArrayListPropertyValue(); else this.propertyValueList propertyValueList; }
// 获取所有propertyValue对象以数组形式返回 public PropertyValue[] getPropertyValues(){ return propertyValueList.toArray(new PropertyValue[0]); }
// 根据name属性值返回对应PropertyValue对象 public PropertyValue getPropertyValues(String propertyName){
// 遍历集合返回 for (PropertyValue propertyValue : propertyValueList) { if(propertyValue.getName().equals(propertyName)) return propertyValue; } return null; }
// 判断集合是否为空 public boolean isEmpty(){ return propertyValueList.isEmpty(); }
// 添加PropertyValue对象 public MultiplePropertyValues addPropertyValue(PropertyValue pv){
// 若有则进行覆盖 for (int i 0; i propertyValueList.size(); i) { if(propertyValueList.get(i).getName().equals(pv.getName())){ propertyValueList.set(i,pv); return this;//目的是链式编程 } }
// 添加新的 this.propertyValueList.add(pv); return this; }
// 判断是否有指定name的PropertyValue对象 public boolean contains(String propertyName){ return getPropertyValues(propertyName) ! null; }
// 获取迭代器对象 Override public IteratorPropertyValue iterator() { return propertyValueList.iterator(); }
}7.1.4.3 BeanDefinition类
BeanDefinition类用来封装bean信息主要包含id(bean 名称)class(bean全类名)及子标签property对象数据
public class BeanDefinition { private String id; private String className; private MultiplePropertyValues multiplePropertyValues; public BeanDefinition() { multiplePropertyValues new MultiplePropertyValues(); } 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 MultiplePropertyValues getMultiplePropertyValues() { return multiplePropertyValues; } public void setMultiplePropertyValues(MultiplePropertyValues multiplePropertyValues) { this.multiplePropertyValues multiplePropertyValues; }
}7.4.2 定义注册表类
7.4.2.1 定义BeanDefinitionRegistry接口
BeanDefinitionRegistry接口定义了注册表相关操作定义如下功能
注册BeanDefinition对象到注册表中根据名称从注册表中获取后去BeanDefinition对象从注册表中删除指定名称的BeanDefinition对象判断注册表中是否包含指定名称的BeanDefinition对象获取注册表中BeanDefinition对象个数获取注册表中所有的Bean
public interface BeanDefinitionRegistry { //往注册表中注册bean void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) ; //从注册表删掉指定名称bean void removeBeanDefinition(String beanName) throws Exception; //获取指定名称bean BeanDefinition getBeanDefinition(String beanName) throws Exception; //判断是否包含指定名称bean boolean containsBeanDefinition(String beanName); //获取所有bean String[] getBeanDefinitionNames(); int getBeanDefinitionCount(); boolean isBeanNameInUse(String var1);
}7.4.2.2 SimpleBeanDefinitionRegistry类
public class SimpleBeanDefinitionRegistry implements BeanDefinitionRegistry{
// 创建容器用于存储 MapString,BeanDefinition beanDefinitionMap new HashMapString,BeanDefinition(); Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) { beanDefinitionMap.put(beanName,beanDefinition); } Override public void removeBeanDefinition(String beanName) throws Exception { beanDefinitionMap.remove(beanName); } Override public BeanDefinition getBeanDefinition(String beanName) throws Exception { return beanDefinitionMap.get(beanName); } Override public boolean containsBeanDefinition(String beanName) { return beanDefinitionMap.containsKey(beanName); } Override public String[] getBeanDefinitionNames() { return beanDefinitionMap.keySet().toArray(new String[0]); } Override public int getBeanDefinitionCount() { return beanDefinitionMap.size(); } Override public boolean isBeanNameInUse(String var1) { return beanDefinitionMap.containsKey(var1); }
}7.4.3 定义解析器类
7.4.3.1 BeanDefinitionReader接口
BeanDefinitionReader用来解析配置文件并在注册表中注册bean的信息定义了两规范
获取注册表功能让外界可通过该对象获取注册表对象加载配置文件并注册bean数据
public interface BeanDefinitionReader{//获取注册表对象BeanDefinitionRegistry getRegistry();//加载配置文件斌在注册表中进行注册void loadBeanDefinitions(String configuration);
}7.4.3.2 XmlBeanDefinitionReader类
XmlBeanDefinitionReader类是专门来解析xml配置文件实现了BeanDefinitionReader接口的两个功能。
public class XmlBeanDefinitionReader implements BeanDefinitionReader {
// 声明注册表对象 private BeanDefinitionRegistry registry; public XmlBeanDefinitionReader() { this.registry new SimpleBeanDefinitionRegistry(); } Override public BeanDefinitionRegistry getRegistry() { return registry; } Override public void loadBeanDefinitions(String configuration) throws Exception{
// 使用dom4j进行xml配置文件的解析 SAXReader saxReader new SAXReader();
// 后去类路径下的配置文件 InputStream resourceAsStream XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(configuration); Document document saxReader.read(resourceAsStream);
// 根据Document对象获取根标签对象(beans) Element rootElement document.getRootElement();
// 获取根标签下所有的bean标签对象 ListElement elements rootElement.elements(bean);
// 遍历集合 for (Element element : elements) {
// 获取id属性 String id element.attributeValue(id);
// 获取className String className element.attributeValue(class);
// 将id和className封装到BeanDefinition对象中
// 创建BeanDefinition对象 BeanDefinition beanDefinition new BeanDefinition(); beanDefinition.setId(id); beanDefinition.setClassName(className);
// 创建MultiplePropertyValue对象 MultiplePropertyValues multiplePropertyValues new MultiplePropertyValues();
// 获取bean标签下的所有property标签对象 ListElement propertyElements element.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); multiplePropertyValues.addPropertyValue(propertyValue); }
// 将multiplePropertyValues封装到BeanDefinition中 beanDefinition.setMultiplePropertyValues(multiplePropertyValues);
// 将BeanDefinition注册到注册表中 registry.registerBeanDefinition(id,beanDefinition); } }
}7.4.4 容器相关类
7.4.4.1 BeanFactory接口
该接口定义IOC容器的统一规范即获取bean对象
public interface BeanFactory{//根据bean对象的名称获取bean对象Object getBean(String name) throws Exception;//根据bean对象的名称获取bean对象并进行类型转换T T getBean(String name,Class? extends T clazz) throws Exception;
}7.4.4.2 ApplicationContext接口
该接口的子实现类对bean 对象的创建都是非延时的所以该接口定义refresh方法主要有两功能
加载配置文件根据注册表中BeanDefinition对象封装的数据进行bean对象的创建
public interface ApplicationContext extends BeanFactory{ void refresh()throws Exception;
}7.4.4.3 AbstractApplicationContext接口
作为ApplicationContext接口的子类故该类是非延时加载故需要在该类中定义Map集合作为bean对象存储容器声明BeanDefinition类型变量用来进行xml配置文件解析符合单一职责原则BeanDefinition类型对象创建交由子类实现子类明确创建BeanDefinitionReader
public abstract class AbstractApplicationContext implements ApplicationContext {
// 声明解析器对象 protected BeanDefinitionReader beanDefinitionReader;
// 存储bean容器key存储的bean的id,value是bean对象 protected MapString,Object singletonObject new HashMapString,Object();;
// 存储配置文件路径 String configLocation; public void refresh() throws Exception{
// 加载BeanDefinition beanDefinitionReader.loadBeanDefinitions(configLocation);
// 初始化bean finishBeanInitialization(); } public void finishBeanInitialization() throws Exception{
// 获取注册表对象 BeanDefinitionRegistry registry beanDefinitionReader.getRegistry();
// 获取BeanDefinition对象 String [] beanNames registry.getBeanDefinitionNames();
// 初始化bean for (String beanName : beanNames) { getBean(beanName); } }
}7.4.4.4 ClassPathXmlApplicationContext接口
该类主要是加载类路径下的配置文件并进行bean对象的创建主要有以下功能
在构造方法中创建BeanDefinitionReader对象在构造方法中调用refresh方法用于进行配置文件加载创建bean对象并存储到容器中重写父类中的getBean方法并实现依赖注入
public class ClassPathXmlApplicationContext extends AbstractApplicationContext{ public ClassPathXmlApplicationContext(String configLocation){ this.configLocation configLocation;
// 构建解析器对象 beanDefinitionReader new XmlBeanDefinitionReader(); try { this.refresh(); }catch (Exception exception){ exception.printStackTrace(); } }
// 根据bean对象的名称获取bean对象 Override public Object getBean(String name) throws Exception {
// 判断对象容器中是否包含指定bean对象若包含则返回否则创建 Object object singletonObject.get(name); if(object ! null) return object;
// 获取BeanDefinition对象 BeanDefinitionRegistry registry beanDefinitionReader.getRegistry(); BeanDefinition beanDefinition registry.getBeanDefinition(name);
// 获取bean信息中的className String className beanDefinition.getClassName();
// 通过反射获取对象 Class? clazz Class.forName(className); Object instance clazz.newInstance();
// 进行依赖注入操作 MultiplePropertyValues multiplePropertyValues beanDefinition.getMultiplePropertyValues(); for (PropertyValue propertyValue : multiplePropertyValues) {
// 获取name属性值 String propertyValueName propertyValue.getName();
// 获取value值 String value propertyValue.getValue();
// 获取ref值 String ref propertyValue.getRef(); if(ref ! null !.equals(ref)){
// 获取依赖的对象 Object bean getBean(ref);
// 拼接方法名 String setterMethodByField StringUtils.getSetterMethodByField(propertyValueName);
// 获取所有方法 Method[] methods clazz.getMethods(); for (Method method : methods) { if(method.getName().equals(setterMethodByField))
// 执行setter方法 method.invoke(instance,bean); } } if(value ! null !.equals(value)){
// 拼接方法名 String methodName StringUtils.getSetterMethodByField(propertyValueName);
// 获取method对象 Method method clazz.getMethod(methodName, String.class); method.invoke(instance, value); } }
// 在返回instance对象之前将该对象存储到map容器中 singletonObject.put(name,instance); return instance; } Override 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); }
}7.4.4.5 测试
将前文回顾Spring框架项目中的pom文件的spring-context依赖换为上述新建项目依赖如图 运行后如图
7.4.5 总结
7.4.5.1 使用到的设计模式
工厂模式工厂模式 配置文件单例模式。Spring IOC管理的bean都是单例的此处单例不是通过构造器进行单例构建且框架对每个bean只创建一个对象。模板方法模式。AbstractApplicationContext类中的finishInitialization方法调用getBean方法因为getBean实现和环境有关。迭代器模式。其中MultiplePropertyValyes类使用了迭代器模式因为此类存储并管理PropertyValue对象也属于一个容器。还使用了很多设计模式如AOP使用到了代理模式选择JDK代理或CGLIB代理使用了策略模式还有适配器模式装饰者模式观察者模式等。
7.4.5.2 符合大部分设计原则
7.4.5.3 整个设计和Spring设计还有一定出入
Spring框架底层是很复杂的进行了很深入的封装并对外提供了很好的扩展性自定义Spring IOC容器有两目的
了解Spring底层对对象的大体管理机制了解设计模式在具体开发中的使用以后学习Spring源码通过该案例实现可以降低Spring学习入门成本