Chapter 24 Handwritten Spring Framework

Spring usage review

The data access layer defines the UserDao interface and its sub-implementation classes:

public interface UserDao {
    
    
    public void add();
}
public class UserDaoImpl implements UserDao {
    
    
    public void add() {
    
    
        System.out.println("userDaoImpl ....");
    }
}

Business logic layer , defining the UserService interface and its sub-implementation classes

public interface UserService {
    
    
    public void add();
}

public class UserServiceImpl implements UserService {
    
    


private UserDao userDao;public void setUserDao(UserDao userDao) {
    
    this.userDao = userDao;}public void add() {
    
    System.out.println("userServiceImpl ...");
​        userDao.add();}

}

Define the UserController class and use the main method to simulate the controller layer

public class UserController {
    
    
    public static void main(String[] args) {
    
    
        // 创建Spring容器对象
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 从IOC容器中获取UserService对象
        UserService userService = applicationContext.getBean("userService", UserService.class);
        // 调用UserService对象的add方法
        userService.add();
    }
}

Write configuration files . Write a configuration file named ApplicationContext.xml under the classpath

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="userService" class="com.lsc.service.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>
    <bean id="userDao" class="com.lsc.dao.UserDaoImpl"></bean>
</beans>

The result of running the code is as follows:

userServiceImpl ...
userDaoImpl ....

It can be seen from the above code and results:

  • The userService object is obtained from the applicationContext container object, that is, the userService object is managed by Spring.

  • The add method in the UserDao object is called in the result, which means that the UserDao sub-implementation class object is also managed by Spring.

  • The userDao variable in UserService can be used normally without manual assignment, indicating that it is assigned by Spring

The above three points reflect the IOC and DI of the Spring framework

IOC: Inversion of Control, inversion of control

DI: Dependency Injection, dependency injection

Bean overview

Spring is Bean Oriented Programming (BOP, Bean Oriented Programming), and Beans are at the core of Spring.

  • The Spring IoC container manages dependencies between Bean objects through configuration files or annotations.

  • Beans are to Spring what Objects are to OOP.

Bean in Spring is used to encapsulate a class, as shown in the following configuration:

<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
    <property name="userDao" ref="userDao"></property>
</bean>

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>

Why are Beans so important?

  • Spring hands over Bean objects to a container called IOC for management.
  • The dependencies between Bean objects are reflected in the configuration file and completed by Spring.

Spring IOC related interfaces

  • BeanFactory: defines the basic functional specifications of the IOC container.
  • BeanDefinition: Defines the mapping between Bean objects and element attributes in the configuration file.
  • BeanDefinitionReader: defines the parsing of beans in the Spring configuration file and encapsulates the BeanDefinition object.
  • BeanDefinitionRegistry: The top-level interface of the registration center, and its subclass implementation defines a container for registering BeanDefinition.

BeanFactory interface

The creation of Beans in Spring is a typical factory pattern (simple factory + configuration file). This series of Bean factories is an IOC container.

There are many IOC container implementations in Spring for users to choose from, and their interrelationships are shown in the following figure:

insert image description here

Among them, BeanFactory, as the top-level interface, defines the basic functional specifications of the IOC container. It has three important interfaces:

  • The ListableBeanFactory interface indicates that these beans can be listable.

  • The HierarchicalBeanFactory interface indicates that these beans have an inheritance relationship, that is, each bean may have a parent bean.

  • The AutowireCapableBeanFactory interface defines Bean autowiring rules.

  • The purpose of defining so many interfaces is to distinguish the transfer and conversion of objects during Spring's internal operations, and to impose restrictions on data access to objects.

From the class diagram, we can find that the final default implementation class is DefaultListableBeanFactory, which implements all interfaces.

The most basic IOC container interface is BeanFactory. Take a look at its source code:

public interface BeanFactory {

String FACTORY_BEAN_PREFIX = "&";

// 根据bean的名称获取IOC容器中的的bean对象
Object getBean(String name) throws BeansException;
// 根据bean的名称获取IOC容器中的的bean对象,并指定获取到的bean对象的类型,这样使用时就不需要类型强转
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

// 判断容器中是否包含指定名称的bean对象
boolean containsBean(String name);
// 根据bean的名称判断是否是单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) 
throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) 
throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);

}
  • In BeanFactory, only the basic behavior of the IOC container is defined, and it does not care about how the Bean is defined and loaded.

  • Just as we only care about what products we can get from the factory, we don't care how the factory produces these products.

  • BeanFactory has a very important sub-interface, the ApplicationContext interface, which mainly regulates the non-delayed loading of bean objects in the container, that is, the object bean is initialized when the container object is created and stored in a container.

To know how the factory generates objects, we need to look at the specific IOC container implementation. Spring provides many IOC container implementations:

  • ClassPathXmlApplicationContext: Load the xml configuration file according to the class path and create the IOC container object.
  • FileSystemXmlApplicationContext: Load the xml configuration file according to the system path and create the IOC container object.
  • AnnotationConfigApplicationContext: Load annotation class configuration and create IOC container.

BeanDefinition interface

The Spring IOC container manages various defined Bean objects and their relationships. Bean objects are described by BeanDefinition in Spring implementation, as shown in the following configuration file:

That is, BeanDefinition defines the mapping between Bean objects in Spring and element attributes in the configuration file.

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
<!-- bean标签还有很多属性:scope、init-method、destory-method等。-->

Its inheritance system is as follows:

insert image description here

BeanDefinitionReader interface

The bean parsing process is very complex , and the functions are divided very finely, because there are many places that need to be expanded, and sufficient flexibility must be ensured to cope with possible changes. The analysis of beans is mainly the analysis of Spring configuration files. This parsing process is mainly done through BeanDefinitionReader. The class structure diagram of BeanDefinitionReader in Spring is as follows:

insert image description here

  • AbstractBeanDefinitionReader actually has 3 subclasses, we mainly imitate xml.

Look at the methods defined by the BeanDefinitionReader interface to understand its specific role:

public interface BeanDefinitionReader {

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

@Nullable
ResourceLoader getResourceLoader();

@Nullable
ClassLoader getBeanClassLoader();

BeanNameGenerator getBeanNameGenerator();

/*
 *下面的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;

}

BeanDefinitionRegistry interface

BeanDefinitionReader is used to parse bean definitions and encapsulate BeanDefinition objects.

There are many bean tags defined in the configuration file. Think about it, where are the parsed BeanDefinition objects stored?

  • The answer is the BeanDefinition registration center, and the top-level interface of the registration center is BeanDefinitionRegistry.
public interface BeanDefinitionRegistry extends AliasRegistry {

// 往注册表中注册bean
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;

// 从注册表中删除指定名称的bean
void removeBeanDefinition(String beanName) 
throws NoSuchBeanDefinitionException;

// 获取注册表中指定名称的bean
BeanDefinition getBeanDefinition(String beanName) 
throws NoSuchBeanDefinitionException;

// 判断注册表中是否已经注册了指定名称的bean
boolean containsBeanDefinition(String beanName);

// 获取注册表中所有的bean的名称
String[] getBeanDefinitionNames();

int getBeanDefinitionCount();
boolean isBeanNameInUse(String beanName);

}

The inheritance structure diagram is as follows:

insert image description here

The complete class structure diagram is as follows:

As can be seen from the above figure, the sub-implementation classes of the BeanDefinitionRegistry interface are as follows:

  • SimpleBeanDefinitionRegistry: The following container is defined in this class, which is used to register beans
// key - beanDefinition名称,value- beanDefinition对象
private final Map<String, BeanDefinition> beanDefinitionMap = 
  new ConcurrentHashMap<>(64);
  • DefaultListableBeanFactory: The following container is defined in this class, which is used to register beans
// key - beanDefinition名称,value- beanDefinition对象
private final Map<String, BeanDefinition> beanDefinitionMap = 
  new ConcurrentHashMap<>(256);
  • GenericApplicationContext

Create container

ClassPathXmlApplicationContext loads Bean configuration resources starting from the refresh() method.

The refresh() method is a template method, which specifies the startup process of the IOC container, and some logic should be handed over to its subclasses for implementation. It loads Bean configuration resources, and ClassPathXmlApplicationContext starts the loading process of Bean definitions by the entire IOC container by calling the refresh() method of its parent class AbstractApplicationContext.

Handwriting simulation of Spring IOC core functions

Define Bean-related POJOs

PropertyValue class

The attributes used to encapsulate the Bean are reflected in the configuration file as the attributes of <bean>the subtags of the encapsulation tag.<property>

@Data
@AllArgsConstructor
@NoArgsConstructor
public class PropertyValue {
    
    
    //name属性
    private String name;
    //ref属性
    private String ref;
    //给基本类型和字符串进行赋值
    private String value;
}

MutablePropertyValues 类

A <bean>tag can have <property>multiple subtags.

Define a MutablePropertyValues ​​class to store and manage multiple PropertyValue objects.

/**
 * @BelongsProject: desigin_pattern
 * @BelongsPackage: com.lsc.spring.beans
 * @Author: lsc
 * @CreateTime: 2023-06-01  12:56
 * @Description: 存储和管理多个PropertyValue对象
 * @Version: 1.0
 */
public class MutablePropertyValues implements Iterable<PropertyValue> {
    
    
    private final List<PropertyValue> propertyValueList;

    public MutablePropertyValues() {
    
    
        propertyValueList = new ArrayList<>();
    }
    public MutablePropertyValues(List<PropertyValue> propertyValueList) {
    
    
        if (propertyValueList == null) {
    
    
            this.propertyValueList = new ArrayList<>();
        } else {
    
    
            this.propertyValueList = propertyValueList;
        }
    }
    /**
     * @description: 获取所有的PropertyValue对象
     * @author: lsc
     * @date: 2023/6/1 13:01
     * @param:
     * @return:
     **/
    public PropertyValue[] getPropertyValues(){
    
    
        return propertyValueList.toArray(new PropertyValue[0]);
    }
    /**
     * @description: 根据name属性值获取PropertyValue对象
     * @author: lsc
     * @date: 2023/6/1 13:07
     * @param: [propertyName]
     * @return: com.lsc.spring.beans.factory.PropertyValue
     **/
    public PropertyValue getPropertyValue(String propertyName){
    
    
        for (PropertyValue propertyValue : propertyValueList) {
    
    
            if(propertyValue.getName().equals(propertyName)){
    
    
                return propertyValue;
            }
        }
        return  null;
    }
    /**
     * @description: 判断集合是否为空
     * @author: lsc
     * @date: 2023/6/1 13:14
     * @param: []
     * @return: boolean
     **/
    public boolean isEmpty(){
    
    
        return propertyValueList.isEmpty();
    }
    /**
     * @description: 添加PropertyValue对象
     * @author: lsc
     * @date: 2023/6/1 13:33
     * @param: [pv]
     * @return: 返回自身实现链式编程
     **/
    public MutablePropertyValues addPropertyValue(PropertyValue pv) {
    
    
        //如果集合中已经有了对应的name的对象,则覆盖它
        for (int i = 0; i < propertyValueList.size(); i++) {
    
    
            if(propertyValueList.get(i).getName().equals(pv.getName())){
    
    
                propertyValueList.set(i,pv);
            }
        }
        propertyValueList.add(pv);
        return this;
    }
    /**
     * @description: 判断是否有指定name属性值的对象
     * @author: lsc
     * @date: 2023/6/1 13:39
     * @param: [propertyName]
     * @return: boolean
     **/
    public boolean contains(String propertyName){
    
    
        return getPropertyValue(propertyName)!=null;
    }
    /**
     * @description: 获取迭代器对象
     * @author: lsc
     * @date: 2023/6/1 13:40
     * @param: []
     * @return: java.util.Iterator<com.lsc.spring.beans.factory.PropertyValue>
     **/
    @Override
    public Iterator<PropertyValue> iterator() {
    
    
        return propertyValueList.iterator();
    }
}

BeanDefinition class

The BeanDefinition class is used to encapsulate <bean>the attributes of the tag, mainly including id, class and sub-tag <property>data.

The class attribute is the full class name of the class that needs to be managed by Spring

@Data
public class BeanDefinition {
    private String id;
    private String className;
    private MutablePropertyValues propertyValues;

    public BeanDefinition() {
        propertyValues= new MutablePropertyValues();
    }
}

Define registry related classes

BeanDefinitionRegistry interface

The BeanDefinitionRegistry interface defines the related operations of the registry:

/**
 * 注册表对象
 */
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 class

This class implements the BeanDefinitionRegistry interface and defines the Map collection as the registry container.

/**
 * 注册表接口的子实现类
 */
public class SimpleBeanDefinitionRegistry implements BeanDefinitionRegistry {
    
    
    // 存储BeanDefinition对象的容器
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    @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[0]);
    }
}

Define parser related classes

BeanDefinitionReader interface

BeanDefinitionReader is used to parse configuration files and register bean information in the registry , defining two specifications:

  • Get the registry, the outside world can get the registry object through this method.
  • Load the configuration file and register the bean data.
public interface BeanDefinitionReader {
    
    
    /**
     * @description:获取注册表对象
     * @author: lsc
     * @date: 2023/6/1 14:03
     * @param: []
     * @return: Registry
     **/
    BeanDefinitionRegistry getRegistry();
    /**
     * 加载配置文件并在注册表中进行注册
     */
    void loadBeanDefinitions(String configLocation) throws Exception;
}

XmlBeanDefinitionReader class

The XmlBeanDefinitionReader class is specially used to parse configuration files in xml format and implement the BeanDefinitionReader interface.

public class XmlBeanDefinitionReader implements BeanDefinitionReader {
    
    
    //声明注册表对象
    private BeanDefinitionRegistry registry;

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

    @Override
    public BeanDefinitionRegistry getRegistry() {
    
    
        return registry;
    }
    /**
     * @description: 解析xml文件进行注册bean到注册表中
     * @author: lsc
     * @date: 2023/6/1 14:08
     * @param: 类路径下配置文件的路径
     * @return: void
     **/
    @Override
    public void loadBeanDefinitions(String configLocation) throws Exception {
    
    
         //使用demo4j进行xml配置文件的解析
        SAXReader saxReader = new SAXReader();
        //获取类路径下的配置文件
        ClassLoader classLoader = XmlBeanDefinitionReader.class.getClassLoader();
        InputStream resourceAsStream = classLoader.getResourceAsStream(configLocation);
        Document document = saxReader.read(resourceAsStream);
        //根据document对象获取根路径标签对象beans
        Element rootElement = document.getRootElement();
        //获取根标签下所有的bean标签对象
        List<Element> beanElements = rootElement.elements("bean");
        //封装BeanDefinition对象,并添加到注册表中
        for (Element beanElement : beanElements) {
    
    
            //1封装BeanDefinition
            BeanDefinition beanDefinition = new BeanDefinition();
            String id = beanElement.attributeValue("id");
            String className = beanElement.attributeValue("class");
            beanDefinition.setId(id);
            beanDefinition.setClassName(className);
            //创建MutablePropertyValues对象
            MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
            // 获取bean标签下所有的property标签对象
            List<Element> propertyElements = beanElement.elements("property");
            for (Element propertyElement : propertyElements) {
    
    
                PropertyValue propertyValue = new PropertyValue(
                        propertyElement.attributeValue("name"),
                        propertyElement.attributeValue("ref"),
                        propertyElement.attributeValue("value")
                );
                mutablePropertyValues.addPropertyValue(propertyValue);
            };
            beanDefinition.setPropertyValues(mutablePropertyValues);
            registry.registerBeanDefinition(id,beanDefinition);
        }
    }
}

IOC container related classes

BeanFactory interface

This interface defines the uniform specification of the IOC container, that is, to obtain the bean object.

public interface BeanFactory {
    
    
    /**
     * 根据bean对象的名称获取bean对象
     */
    Object getBean(String name) throws Exception;
    /**
     * 根据bean对象的名称获取bean对象,并进行类型转换
     */
    <T> T getBean(String name, Class<? extends T> clazz) throws Exception;
}

ApplicationContext interface

This interface is a sub-interface of BeanFactory, and its implementation classes are non-delayed in the creation of bean objects.

  • Non-delay: When creating a Spring container object, the configuration file will be loaded, and the bean will be initialized and placed in the container.

Define the refresh() method in this interface, which mainly completes the following two functions:

  • Load configuration file.
  • The bean object is created according to the data encapsulated by the BeanDefinition object in the registry.
/**
 * 定义非延时加载功能
 */
public interface ApplicationContext extends BeanFactory {
    
    
    /**
     * 加载配置文件并创建对象
     */
    void refresh() throws Exception;
}

AbstractApplicationContext 类

A Map collection needs to be defined in this class as a bean object storage container .

As a subclass of the ApplicationContext interface, this class is non-delayed loading.

Declare a variable of type BeanDefinitionReader, which is used to parse the xml configuration file, and conforms to the principle of single responsibility. The creation of BeanDefinitionReader objects is left to the subclass, because only the subclass knows which implementation class object of BeanDefinitionReader should be created (either xml or properties).

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() throws Exception {
    
    
        //加载BeanDefinition对象
        beanDefinitionReader.loadBeanDefinitions(configLocation);
        //初始化bean
        finishBeanInitialization();
    }

    private void finishBeanInitialization() throws Exception {
    
    
        //获取注册表对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        //获取BeanDefinition对象
        String[] beanNames = registry.getBeanDefinitionNames();
        //bean的初始化
        for (String beanName : beanNames) {
    
    
            getBean(beanName);
        }

    }
}

finishBeanInitialization()The method called in the method of this class getBean()uses the template method pattern.

ClassPathXmlApplicationContext 类

This class mainly loads configuration files under the class path and creates bean objects, mainly completing the following functions:

  • In the constructor, create a BeanDefinitionReader object.
  • In the construction method, call the refresh() method, which is used to load the configuration file, create the bean object and store it in the container.
  • Override the getBean() method in the parent interface and implement dependency injection operations.
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {
    
    
    public ClassPathXmlApplicationContext(String configLocation) {
    
    
        this.configLocation=configLocation;
        //构造解释器对象
        beanDefinitionReader = new XmlBeanDefinitionReader();
        try {
    
    
            this.refresh();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

    @Override
    public Object getBean(String name) throws Exception {
    
    
        //对象容器中有指定名称的bean的对象,就直接返回,不包含咨询创建
        Object o = singletonObjects.get(name);
        if(o!=null){
    
    
            return o;
        }
        //从注册表中获取BeanDefinition对象, 然后拿到类路径创建对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        String className = beanDefinition.getClassName();
        //通过反射创建对象
        Class<?> aClass = Class.forName(className);
        Object beanObj = aClass.newInstance();
        //进行依赖注入
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues) {
    
    
            String pName = propertyValue.getName();
            String value = propertyValue.getValue();
            String ref = propertyValue.getRef();
            if(ref!=null && !"".equals(ref)){
    
    
                //获取依赖的bean对象
                Object bean = getBean(ref);
                // 获取到setter方法:userDao ==> setUserDao
                String setterMethodByFieldName = StringUtils.getSetterMethodByFieldName(pName);
                //获取到setter方法
                Method[] methods = aClass.getMethods();
                for (Method method : methods) {
    
    
                    if(setterMethodByFieldName.equals(method.getName())){
    
    
                        method.invoke(beanObj,bean);
                    }
                }
            }
            if (value != null && !"".equals(value)) {
    
    
                // 获取到setter方法:age ==> setAge, 并执行
                String methodName = StringUtils.getSetterMethodByFieldName(pName);
                Method method = aClass.getMethod(methodName, String.class);
                method.invoke(beanObj, value);
            }


        }
        // 返回之前将该对象存储到map容器中,下次可以直接取,达到单例效果
        singletonObjects.put(name, beanObj);
        return null;
    }

    @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);
    }
}
public class StringUtils {
    
    
    private StringUtils() {
    
    
    }

    // userDao ==> setUserDao
    public static String getSetterMethodByFieldName(String fieldName) {
    
    
        return "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    }
}

Summarize

Using the custom Spring framework above, you can directly replace the previous code using Spring (realize the simplest function of Spring).

Design patterns used:

  • Factory mode. A simple factory + configuration file is used here.

  • Singleton pattern. The bean objects managed by Spring IOC are all singletons. The singleton here is not controlled by the constructor, but the Spring framework only creates one object for each bean (controlled by the Map container).

  • Template method pattern. The finishBeanInitialization() method in the AbstractApplicationContext class calls the getBean() method of the subclass, because the implementation of getBean() is closely related to the environment (the methods of parsing and obtaining bean objects for different configuration files are different).

  • Iterator pattern. The iterator pattern is used in the MutablePropertyValues ​​class definition. Because this class stores and manages PropertyValue objects and also belongs to a container, it provides a traversal method for the container.

The real Spring framework actually uses many design patterns, such as AOP using proxy mode, choosing JDK proxy or CGLIB proxy using strategy mode, adapter mode, decorator mode, observer mode, etc.

Note that the Spring we wrote ourselves is somewhat different in design from the real Spring.

The bottom layer of the Spring framework is very complex, it has been deeply encapsulated, and it provides good scalability to the outside world.

Customizing SpringIOC has the following purposes:

  • Understand the general management mechanism of Spring's underlying objects.
  • Understand the use of design patterns in specific development.
  • To pave the way for learning Spring source code.

Guess you like

Origin blog.csdn.net/qq_50985215/article/details/130990093