当前位置: 首页 > news >正文

【设计模式精讲】开源实战之剖析Spring框架:结合设计模式自定义SpringIOC

文章目录

  • 第七章 开源实战
    • 7.1 剖析Spring框架中用到的经典设计模式
      • 7.1.3 结合设计模式自定义SpringIOC
        • 7.1.3.1 Spring IOC核心组件
        • 7.1.3.2 IOC流程图
        • 7.1.3.3 自定义SpringIOC
          • 1) 创建与Bean相关的pojo类
          • 2) 创建注册表相关的类
          • 3) 创建解析器相关的类
          • 4) 创建IOC容器相关的类
          • 5) 自定义IOC容器测试
          • 6) 案例中使用到的设计模式

在这里插入图片描述
个人主页:道友老李
欢迎加入社区:道友老李的学习社区

第七章 开源实战

7.1 剖析Spring框架中用到的经典设计模式

7.1.3 结合设计模式自定义SpringIOC

7.1.3.1 Spring IOC核心组件

1) BeanFactory

BeanFactory作为最顶层的一个接口,定义了IoC容器的基本功能规范

在这里插入图片描述

从类图中我们可以发现最终的默认实现类是DefaultListableBeanFactory,它实现了所有的接口。那么为何要定义这么多层次的接口呢?
每个接口都有它的使用场合,主要是为了区分在Spring内部操作过程中对象的传递和转化,对对象的数据访问所做的限制。

例如,

  • ListableBeanFactory接口表示这些Bean可列表化。
  • HierarchicalBeanFactory表示这些Bean 是有继承关系的,也就是每个 Bean 可能有父 Bean
  • AutowireCapableBeanFactory 接口定义Bean的自动装配规则。

这三个接口共同定义了Bean的集合、Bean之间的关系及Bean行为。

在BeanFactory里只对IoC容器的基本行为做了定义,根本不关心你的Bean是如何定义及怎样加载的。正如我们只关心能从工厂里得到什么产品,不关心工厂是怎么生产这些产品的。

2 ) ApplicationContext

BeanFactory有一个很重要的子接口,就是ApplicationContext接口,该接口主要来规范容器中的bean对象是非延时加载,即在创建容器对象的时候就对象bean进行初始化,并存储到一个容器中。

//延时加载
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("bean.xml"));

//立即加载
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
User user = context.getBean("user", User.class);

ApplicationContext 的子类主要包含两个方面:

  • ConfigurableApplicationContext 表示该 Context 是可修改的,也就是在构建 Context 中用户可以动态添加或修改已有的配置信息

  • WebApplicationContext 顾名思义,就是为 web 准备的 Context 他可以直接访问到 ServletContext,通常情况下,这个接口使用少

要知道工厂是如何产生对象的,我们需要看具体的IoC容器实现,Spring提供了许多IoC容器实现,比如:

  • ClasspathXmlApplicationContext : 根据类路径加载xml配置文件,并创建IOC容器对象。
  • FileSystemXmlApplicationContext :根据系统路径加载xml配置文件,并创建IOC容器对象。
  • AnnotationConfigApplicationContext :加载注解类配置,并创建IOC容器。

在这里插入图片描述

总体来说 ApplicationContext 必须要完成以下几件事:

  • 标识一个应用环境
  • 利用 BeanFactory 创建 Bean 对象
  • 保存对象关系表
  • 能够捕获各种事件

3) Bean定义:BeanDefinition

这里的 BeanDefinition 就是我们所说的 Spring 的 Bean,我们自己定义的各个 Bean 其实会转换成一个个 BeanDefinition 存在于 Spring 的 BeanFactory 中

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
	//DefaultListableBeanFactory 中使用 Map 结构保存所有的 BeanDefinition 信息
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); 
}   

BeanDefinition 中保存了我们的 Bean 信息,比如这个 Bean 指向的是哪个类、是否是单例的、是否懒加载、这个 Bean 依赖了哪些 Bean 等等。

4) BeanDefinitionReader

Bean的解析过程非常复杂,功能被分得很细,因为这里需要被扩展的地方很多,必须保证足够的灵活性,以应对可能的变化。Bean的解析主要就是对Spring配置文件的解析。

这个解析过程主要通过BeanDefinitionReader来完成,看看Spring中BeanDefinitionReader的类结构图,如下图所示。

在这里插入图片描述

BeanDefinitionReader接口定义的功能

public interface BeanDefinitionReader {

	/*
		下面的loadBeanDefinitions都是加载bean定义,从指定的资源中
	*/
	int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
	int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
	int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
	int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}

5) BeanFactory后置处理器

后置处理器是一种拓展机制,贯穿Spring Bean的生命周期

后置处理器分为两类:

BeanFactory后置处理器:BeanFactoryPostProcessor

实现该接口,可以在spring的bean创建之前,修改bean的定义属性

在这里插入图片描述

public interface BeanFactoryPostProcessor {

    /*
     *  该接口只有一个方法postProcessBeanFactory,方法参数是ConfigurableListableBeanFactory,通过该
        参数,可以获取BeanDefinition
    */
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

6) Bean后置处理器:BeanPostProcessor

BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口

实现该接口,可以在spring容器实例化bean之后,在执行bean的初始化方法前后,添加一些处理逻辑

在这里插入图片描述

public interface BeanPostProcessor {
    //bean初始化方法调用前被调用
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    //bean初始化方法调用后被调用
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
7.1.3.2 IOC流程图

在这里插入图片描述

  1. 容器环境的初始化(系统、JVM 、解析器、类加载器等等)
  2. Bean工厂的初始化(IOC容器首先会销毁旧工厂,旧Bean、创建新的工厂)
  3. 读取:通过BeanDefinitonReader读取我们项目中的配置(application.xml)
  4. 定义:通过解析xml文件内容,将里面的Bean解析成BeanDefinition(未实例化、未初始化)
  5. 将解析得到的BeanDefinition,存储到工厂类的Map容器中
  6. 调用 BeanFactoryPostProcessor 该方法是一种功能增强,可以在这个步骤对已经完成初始化的 BeanFactory 进行属性覆盖,或是修改已经注册到 BeanFactory 的 BeanDefinition
  7. 通过反射实例化bean对象
  8. 进入到Bean实例化流程,首先设置对象属性
  9. 检查Aware相关接口,并设置相关依赖
  10. 前置处理器,执行BeanPostProcesser的before方法对bean进行扩展
  11. 检查是否有实现initializingBean 回调接口,如果实现就要回调其中的AftpropertiesSet() 方法,(通过可以完成一些配置的加载)
  12. 检查是否有配置自定义的init-method ,
  13. 后置处理器执行BeanPostProcesser 的after方法 --> AOP就是在这个阶段完成的, 在这里判断bean对象是否实现接口,实现就使用JDK代理,否则选择CGLIB
  14. 对象创建完成,添加到BeanFactory的单例池中
7.1.3.3 自定义SpringIOC

对下面的配置文件进行解析,并自定义SpringIOC, 对涉及到的对象进行管理。

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="courseService" class="com.mashibing.service.impl.CourseServiceImpl">
        <property name="courseDao" ref="courseDao"></property>
    </bean>
    <bean id="courseDao" class="com.mashibing.dao.impl.CourseDaoImpl"></bean>
</beans>
1) 创建与Bean相关的pojo类
  • PropertyValue类: 用于封装bean的属性,体现到上面的配置文件就是封装bean标签的子标签property标签数据。
package com.mashibing.framework.beans;

/**
 * 该类用来封装bean标签下的property子标签的属性
 *      1.name属性
 *      2.ref属性
 *      3.value属性: 给基本数据类型及string类型数据赋的值
 * @author spikeCong
 * @date 2022/10/26
 **/
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;
    }
}
  • MutablePropertyValues类: 一个bean标签可以有多个property子标签,所以再定义一个MutablePropertyValues类,用来存储并管理多个PropertyValue对象。
package com.mashibing.framework.beans;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * 该类用来存储和遍历多个PropertyValue对象
 * @author spikeCong
 * @date 2022/10/26
 **/
public class MutablePropertyValues implements Iterable<PropertyValue>{

    //定义List集合,存储PropertyValue的容器
    private final List<PropertyValue> propertyValueList;

    //空参构造中 初始化一个list
    public MutablePropertyValues() {
        this.propertyValueList = new ArrayList<PropertyValue>();
    }

    //有参构造 接收一个外部传入的list,赋值propertyValueList属性
    public MutablePropertyValues(List<PropertyValue> propertyValueList) {
        if(propertyValueList == null){
            this.propertyValueList = new ArrayList<PropertyValue>();
        }else{
            this.propertyValueList = propertyValueList;
        }
    }

    //获取当前容器对应的迭代器对象
    @Override
    public Iterator<PropertyValue> iterator() {

        //直接获取List集合中的迭代器
        return propertyValueList.iterator();
    }

    //获取所有的PropertyValue
    public PropertyValue[] getPropertyValues(){
        //将集合转换为数组并返回
        return propertyValueList.toArray(new PropertyValue[0]); //new PropertyValue[0]声明返回的数组类型
    }

    //根据name属性值获取PropertyValue
    public PropertyValue getPropertyValue(String propertyName){
        //遍历集合对象
        for (PropertyValue propertyValue : propertyValueList) {
            if(propertyValue.getName().equals(propertyName)){
                return propertyValue;
            }
        }

        return null;
    }

    //判断集合是否为空,是否存储PropertyValue
    public boolean isEmpty(){
        return propertyValueList.isEmpty();
    }

    //向集合中添加
    public MutablePropertyValues addPropertyValue(PropertyValue value){
        //判断集合中存储的propertyvalue对象.是否重复,重复就进行覆盖
        for (int i = 0; i < propertyValueList.size(); i++) {
            //获取集合中每一个 PropertyValue
            PropertyValue currentPv = propertyValueList.get(i);

            //判断当前的pv的name属性 是否与传入的相同,如果相同就覆盖
            if(currentPv.getName().equals(value.getName())){
                propertyValueList.set(i,value);
                return this;
            }
        }

        //没有重复
        this.propertyValueList.add(value);
        return this;  //目的是实现链式编程
    }

    //判断是否有指定name属性值的对象
    public boolean contains(String propertyName){
        return getPropertyValue(propertyName) != null;
    }
}
  • BeanDefinition类: 用来封装bean信息的,主要包含id(即bean对象的名称)、class(需要交由spring管理的类的全类名)及子标签property数据。
/**
 * 封装Bean标签数据的类,包括id与class以及子标签的数据
 * @author spikeCong
 * @date 2022/10/27
 **/
public class BeanDefinition {

    private String id;

    private String className;

    private MutablePropertyValues propertyValues;

    public BeanDefinition() {
        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) 创建注册表相关的类

BeanDefinition对象存取的操作, 其实是在BeanDefinitionRegistry接口中定义的,它被称为是BeanDefinition的注册中心.

//源码
public interface BeanDefinitionRegistry extends AliasRegistry {

	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;

	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	boolean containsBeanDefinition(String beanName);

	String[] getBeanDefinitionNames();
    
	int getBeanDefinitionCount();
    
	boolean isBeanNameInUse(String beanName);
}

BeanDefinitionRegistry继承结构图如下:

在这里插入图片描述

BeanDefinitionRegistry接口的子实现类主要有以下两个:

  • DefaultListableBeanFactory

    在该类中定义了如下代码,就是用来注册bean

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    
  • SimpleBeanDefinitionRegistry

    在该类中定义了如下代码,就是用来注册bean

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);
    
  • 自定义BeanDefinitionRegistry接口定义了注册表的相关操作,定义如下功能:

public interface BeanDefinitionRegistry {

    //注册BeanDefinition对象到注册表中
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);

    //从注册表中删除指定名称的BeanDefinition对象
    void removeBeanDefinition(String beanName) throws Exception;

    //根据名称从注册表中获取BeanDefinition对象
    BeanDefinition getBeanDefinition(String beanName) throws Exception;

    //判断注册表中是否包含指定名称的BeanDefinition对象
    boolean containsBeanDefinition(String beanName);

    //获取注册表中BeanDefinition对象的个数
    int getBeanDefinitionCount();

    //获取注册表中所有的BeanDefinition的名称
    String[] getBeanDefinitionNames();
}
  • SimpleBeanDefinitionRegistry类, 该类实现了BeanDefinitionRegistry接口,定义了Map集合作为注册表容器。
public class SimpleBeanDefinitionRegistry implements BeanDefinitionRegistry {

    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<String, 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 int getBeanDefinitionCount() {
        return beanDefinitionMap.size();
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return beanDefinitionMap.keySet().toArray(new String[1]);
    }
}
3) 创建解析器相关的类

BeanDefinitionReader接口

  • BeanDefinitionReader用来解析配置文件并在注册表中注册bean的信息。定义了两个规范:
    • 获取注册表的功能,让外界可以通过该对象获取注册表对象
    • 加载配置文件,并注册bean数据
/**
 * 该类定义解析配置文件规则的接口
 **/
public interface BeanDefinitionReader {

    //获取注册表对象
    BeanDefinitionRegistry getRegistry();

    //加载配置文件并在注册表中进行注册
    void loadBeanDefinitions(String configLocation) throws Exception;
}

XmlBeanDefinitionReader类

  • XmlBeanDefinitionReader是专门用来解析xml配置文件的。该类实现BeanDefinitionReader接口并实现接口中的两个功能。
/**
 * 该类是对XML文件进行解析的类
 **/
public class XmlBeanDefinitionReader implements BeanDefinitionReader {

    //声明注册表对象(将配置文件与注册表解耦,通过Reader降低耦合性)
    private BeanDefinitionRegistry registry;

    public XmlBeanDefinitionReader() {
        registry = new SimpleBeanDefinitionRegistry();
    }

    @Override
    public BeanDefinitionRegistry getRegistry() {
        return registry;
    }

    //加载配置文件
    @Override
    public void loadBeanDefinitions(String configLocation) throws Exception {
        //使用dom4j解析xml
        SAXReader reader = new SAXReader();

        //获取配置文件,类路径下
        InputStream is = XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(configLocation);

        //获取document文档对象
        Document document = reader.read(is);

        Element rootElement = document.getRootElement();
        //解析bean标签
        parseBean(rootElement);
    }

    private void parseBean(Element rootElement) {

        //获取所有的bean标签
        List<Element> elements = rootElement.elements();

        //遍历获取每个bean标签的属性值和子标签property
        for (Element element : elements) {

            String id = element.attributeValue("id");
            String className = element.attributeValue("class");

            //封装到beanDefinition
            BeanDefinition beanDefinition = new BeanDefinition();
            beanDefinition.setId(id);
            beanDefinition.setClassName(className);

            //获取property
            List<Element> list = element.elements("property");

            MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();

            //遍历,封装propertyValue,并保存到mutablePropertyValues
            for (Element element1 : list) {
                String name = element1.attributeValue("name");
                String ref = element1.attributeValue("ref");
                String value = element1.attributeValue("value");
                PropertyValue propertyValue = new PropertyValue(name,ref,value);
                mutablePropertyValues.addPropertyValue(propertyValue);
            }

            //将mutablePropertyValues封装到beanDefinition
            beanDefinition.setPropertyValues(mutablePropertyValues);

            System.out.println(beanDefinition);
            //将beanDefinition注册到注册表
            registry.registerBeanDefinition(id,beanDefinition);
        }
    }
}
4) 创建IOC容器相关的类

1) BeanFactory接口

在该接口中定义IOC容器的统一规范和获取bean对象的方法。

/**
 * IOC容器父接口
 **/
public interface BeanFactory {

    Object getBean(String name)throws Exception;

    //泛型方法,传入当前类或者其子类
    <T> T getBean(String name ,Class<? extends T> clazz)throws Exception;
}

2) ApplicationContext接口

该接口的所有的子实现类对bean对象的创建都是非延时的,所以在该接口中定义 refresh() 方法,该方法主要完成以下两个功能:

  • 加载配置文件。
  • 根据注册表中的BeanDefinition对象封装的数据进行bean对象的创建。
/**
 * 定义非延时加载功能
 **/
public interface ApplicationContext extends BeanFactory {

    //进行配置文件加载,并进行对象创建
    void refresh();
}

3) AbstractApplicationContext类

  • 作为ApplicationContext接口的子类,所以该类也是非延时加载,所以需要在该类中定义一个Map集合,作为bean对象存储的容器。
  • 声明BeanDefinitionReader类型的变量,用来进行xml配置文件的解析,符合单一职责原则。
  • BeanDefinitionReader类型的对象创建交由子类实现,因为只有子类明确到底创建BeanDefinitionReader哪儿个子实现类对象。
/**
 * ApplicationContext接口的子实现类
 *      创建容器对象时,加载配置文件,对bean进行初始化
 **/
public abstract class AbstractApplicationContext implements ApplicationContext {

    //声明解析器变量
    protected BeanDefinitionReader beanDefinitionReader;

    //定义存储bean对象的Map集合
    protected Map<String,Object> singletonObjects = new HashMap<>();

    //声明配置文件类路径的变量
    protected String configLocation;

    @Override
    public void refresh() {

        //加载beanDefinition对象
        try {
            beanDefinitionReader.loadBeanDefinitions(configLocation);
            //初始化bean
            finishBeanInitialization();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //bean初始化
    protected  void finishBeanInitialization() throws Exception {
        //获取对应的注册表对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();

        //获取beanDefinition对象
        String[] beanNames = registry.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            //进行bean的初始化
            getBean(beanName);
        }
    };
}

4) ClassPathXmlApplicationContext类

该类主要是加载类路径下的配置文件,并进行bean对象的创建,主要完成以下功能:

  • 在构造方法中,创建BeanDefinitionReader对象。
  • 在构造方法中,调用refresh()方法,用于进行配置文件加载、创建bean对象并存储到容器中。
  • 重写父接口中的getBean()方法,并实现依赖注入操作。
/**
 * IOC容器具体的子实现类,加载XML格式配置文件
 **/
public class ClassPathXmlApplicationContext extends AbstractApplicationContext{

    public ClassPathXmlApplicationContext(String configLocation) {
        this.configLocation = configLocation;
        //构建解析器对象
        this.beanDefinitionReader = new XmlBeanDefinitionReader();

        this.refresh();
    }

    //跟据bean的对象名称获取bean对象
    @Override
    public Object getBean(String name) throws Exception {
        //判断对象容器中是否包含指定名称的bean对象,如果包含就返回,否则自行创建
        Object obj = singletonObjects.get(name);
        if(obj != null){
            return obj;
        }

        //自行创建,获取beanDefinition对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);

        //通过反射创建对象
        String className = beanDefinition.getClassName();
        Class<?> clazz = Class.forName(className);
        Object beanObj = clazz.newInstance();

        //CourseService与UserDao存依赖,所以要将UserDao一同初始化,进行依赖注入
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues) {
            //获取name属性值
            String propertyName = propertyValue.getName();
            //获取Value属性
            String value = propertyValue.getValue();
            //获取ref属性
            String ref = propertyValue.getRef();

            //ref与value只能存在一个
            if(ref != null && !"".equals(ref)){
                //获取依赖的bean对象,拼接set set+Course
                Object bean = getBean(ref);
                String methodName = StringUtils.getSetterMethodFieldName(propertyName);

                //获取所有方法对象
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if(methodName.equals(method.getName())){
                        //执行该set方法
                        method.invoke(beanObj,bean);
                    }
                }
            }

            if(value != null && !"".equals(value)){
                String methodName = StringUtils.getSetterMethodFieldName(propertyName);
                //获取method
                Method method = clazz.getMethod(methodName, String.class);
                method.invoke(beanObj,value);
            }
        }

        //在返回beanObj之前 ,需要将对象存储到Map容器中
        this.singletonObjects.put(name,beanObj);


        return beanObj;
    }

    @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);
    }
}
5) 自定义IOC容器测试

第一步: 将我们写好的自定义IOC容器项目,安装到maven仓库中,使其他项目可以引入其依赖

//依赖信息
<dependencies>
    <dependency>
        <groupId>com.mashibing</groupId>
        <artifactId>user_defined_springioc</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

第二步: 创建一个新的maven项目,引入上面的依赖,项目结构如下

第三步: 完成代码编写

  • dao
public interface CourseDao {
    public void add();
}

public class CourseDaoImpl implements CourseDao {

    //value注入
    private String courseName;

    public String getCourseName() {
        return courseName;
    }

    public void setCourseName(String courseName) {
        this.courseName = courseName;
    }

    public CourseDaoImpl() {
        System.out.println("CourseDaoImpl创建了......");
    }

    @Override
    public void add() {
        System.out.println("CourseDaoImpl的add方法执行了......" + courseName);
    }
}
  • service
public interface CourseService {

    public void add();
}

public class CourseServiceImpl implements CourseService {

    public CourseServiceImpl() {
        System.out.println("CourseServiceImpl创建了......");
    }

    private CourseDao courseDao;

    public void setCourseDao(CourseDao courseDao) {
        this.courseDao = courseDao;
    }

    @Override
    public void add() {
        System.out.println("CourseServiceImpl的add方法执行了......");
        courseDao.add();
    }
}
  • applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="courseService" class="com.mashibing.test_springioc.service.impl.CourseServiceImpl">
        <property name="courseDao" ref="courseDao"></property>
    </bean>
    <bean id="courseDao" class="com.mashibing.test_springioc.dao.impl.CourseDaoImpl">
        <property name="courseName" value="java"></property>
    </bean>
</beans>
  • Controller
public class CourseController{

    public static void main(String[] args) {
        //1.创建Spring的容器对象
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2.从容器对象中获取CourseService对象
        CourseService courseService = context.getBean("courseService", CourseService.class);

        //3.调用UserService的add方法
        courseService.add();
    }
}
6) 案例中使用到的设计模式
  • 工厂模式。这个使用工厂模式 + 配置文件的方式。
  • 单例模式。Spring IOC管理的bean对象都是单例的,此处的单例不是通过构造器进行单例的控制的,而是spring框架对每一个bean只创建了一个对象。
  • 模板方法模式。AbstractApplicationContext类中的finishBeanInitialization()方法调用了子类的getBean()方法,因为getBean()的实现和环境息息相关。
  • 迭代器模式。对于MutablePropertyValues类定义使用到了迭代器模式,因为此类存储并管理PropertyValue对象,也属于一个容器,所以给该容器提供一个遍历方式。

相关文章:

  • 基于fast-whisper模型的语音识别工具的设计与实现
  • 【MongoDB】在Windows11下安装与使用
  • 2024年12月中国电子学会青少年软件编程(Python)等级考试试卷(二级)真题 + 答案
  • FFmpeg-chapter2-C++中的线程
  • 【AVRCP】深入理解蓝牙音频 / 视频远程控制规范:从基础到应用
  • weaviate 安装与测试
  • C# .NET Core HttpClient 和 HttpWebRequest 使用
  • windows服务器更新jar包脚本
  • 【pytest框架源码分析三】pluggy源码分析之hook注册调用流程
  • Compose笔记(七)--Modifier
  • 《算法笔记》9.6小节 数据结构专题(2)并查集 问题 C: How Many Tables
  • EasyExcel构建复杂多级表头
  • 网络安全员证书
  • go类(结构体)和对象
  • windows下玩转vllm:在wsl下安装vllm
  • 高速光耦在通信行业的应用(四) | 1Mbps通信光耦的应用
  • sentinel详细使用教学
  • 两分种解决:xshell终端delete键无效
  • c++中的静态多态和动态多态简介
  • 性能测试【Perfdog】
  • 免费阅读网站软件/百度搜索量查询
  • 动态模板网站建设/推广普通话奋进新征程手抄报
  • 网站开发的后期支持/网站模板购买
  • 在线做头像网站/代发关键词排名包收录
  • vs做网站怎么调试/深圳关键词排名优化系统
  • 肃宁县网站建设价格/营销推广方案怎么写