Mr. Cappuccino的第59杯咖啡——简单手写SpringIOC框架

简单手写SpringIOC框架

    • 环境搭建
      • 基于XML方式
        • 项目结构
        • 项目代码
        • 运行结果
      • 基于注解方式
        • 项目结构
        • 项目代码
        • 运行结果
    • 简单手写SpringIOC框架
      • 核心原理
      • 基于XML方式
        • 原理
        • 项目结构
        • 项目代码
        • 运行结果
      • 基于注解方式
        • 原理
        • 项目结构
        • 项目代码
        • 运行结果

环境搭建

基于XML方式

项目结构

Mr. Cappuccino的第59杯咖啡——简单手写SpringIOC框架_第1张图片

项目代码

pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>comgroupId>
    <artifactId>springartifactId>
    <version>1.0-SNAPSHOTversion>

    <properties>
        <maven.compiler.source>8maven.compiler.source>
        <maven.compiler.target>8maven.compiler.target>
    properties>

    <dependencies>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-coreartifactId>
            <version>5.2.1.RELEASEversion>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-beansartifactId>
            <version>5.2.1.RELEASEversion>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>5.2.1.RELEASEversion>
        dependency>
    dependencies>

project>

UserBean.java

package com.spring.bean;

/**
 * @author honey
 * @date 2023-08-08 14:58:16
 */
public class UserBean {
}

spring.xml


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userBean" class="com.spring.bean.UserBean"/>

beans>

SpringTest01.java

package com.spring.test;

import com.spring.bean.UserBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author honey
 * @date 2023-08-08 14:59:56
 */
public class SpringTest01 {

    public static void main(String[] args) {
        // 读取spring.xml
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        // 从IOC容器中读取对象
        UserBean userBean = applicationContext.getBean("userBean", UserBean.class);
        System.out.println(userBean);
    }
}

运行结果

Mr. Cappuccino的第59杯咖啡——简单手写SpringIOC框架_第2张图片

基于注解方式

项目结构

Mr. Cappuccino的第59杯咖啡——简单手写SpringIOC框架_第3张图片

项目代码

ScanBean.java

package com.spring.bean.scan;

import org.springframework.stereotype.Component;

/**
 * @author honey
 * @date 2023-08-08 16:37:26
 */
@Component
public class ScanBean {
}

SpringConfig.java

package com.spring.config;

import com.spring.bean.UserBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author honey
 * @date 2023-08-08 16:30:21
 */
@Configuration
@ComponentScan(value = {"com.spring.bean.scan"})
public class SpringConfig {

    @Bean(name = "user")
    public UserBean userBean() {
        return new UserBean();
    }
}

SpringTest02.java

package com.spring.test;

import com.spring.bean.UserBean;
import com.spring.bean.scan.ScanBean;
import com.spring.config.SpringConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author honey
 * @date 2023-08-08 16:31:25
 */
public class SpringTest02 {

    public static void main(String[] args) {
        // 加载SpringConfig
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        // 从IOC容器中读取对象
        UserBean userBean = applicationContext.getBean("user", UserBean.class);
        System.out.println(userBean);
        ScanBean scanBean = applicationContext.getBean("scanBean", ScanBean.class);
        System.out.println(scanBean);
    }
}

运行结果

Mr. Cappuccino的第59杯咖啡——简单手写SpringIOC框架_第4张图片

简单手写SpringIOC框架

核心原理

底层使用map集合管理对象,key=beanId,value=实例对象

private final Map<String, Object> beanMap = new ConcurrentHashMap<>();

基于XML方式

原理

基于反射+工厂模式+DOM技术

  1. 使用DOM技术解析spring.xml文件;
  2. 获取bean的id和class属性;
  3. 根据类的完整路径使用反射技术初始化对象;
  4. 使用工厂模式管理初始化对象;

项目结构

Mr. Cappuccino的第59杯咖啡——简单手写SpringIOC框架_第5张图片

项目代码

pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>comgroupId>
    <artifactId>ext-spring-iocartifactId>
    <version>1.0-SNAPSHOTversion>

    <properties>
        <maven.compiler.source>8maven.compiler.source>
        <maven.compiler.target>8maven.compiler.target>
    properties>

    <dependencies>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-coreartifactId>
            <version>5.2.1.RELEASEversion>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-beansartifactId>
            <version>5.2.1.RELEASEversion>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>5.2.1.RELEASEversion>
        dependency>
        <dependency>
            <groupId>dom4jgroupId>
            <artifactId>dom4jartifactId>
            <version>1.6.1version>
        dependency>
    dependencies>

project>

UserBean.java

package com.spring.bean;

/**
 * @author honey
 * @date 2023-08-08 16:56:32
 */
public class UserBean {
}

spring.xml


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userBean" class="com.spring.bean.UserBean"/>

beans>

SpringIocXml.java

package com.spring.ext;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.core.io.ClassPathResource;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author honey
 * @date 2023-08-08 16:57:17
 */
public class SpringIocXml {

    private final Map<String, Object> beanMap = new ConcurrentHashMap<>();

    public SpringIocXml() throws IOException, DocumentException {
        init();
    }

    public <T> T getBean(String name) {
        return (T) beanMap.get(name);
    }

    /**
     * 初始化IOC容器
     */
    private void init() throws IOException, DocumentException {
        // 解析spring.xml配置
        ClassPathResource classPathResource = new ClassPathResource("spring.xml");
        File xmlFile = classPathResource.getFile();
        SAXReader saxReader = new SAXReader();
        Document doc = saxReader.read(xmlFile);
        // 获取根节点
        Element rootElement = doc.getRootElement();
        // 获取bean节点信息
        List<Element> beans = rootElement.elements("bean");
        for (Element bean : beans) {
            try {
                String beanId = bean.attribute("id").getValue();
                String classPath = bean.attribute("class").getValue();
                // 使用反射机制初始化对象,并将对象存入Map集合
                Class<?> clazz = Class.forName(classPath);
                Object object = clazz.newInstance();
                beanMap.put(beanId, object);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

SpringTest01.java

package com.spring.test;

import com.spring.bean.UserBean;
import com.spring.ext.SpringIocXml;
import org.dom4j.DocumentException;

import java.io.IOException;

/**
 * @author honey
 * @date 2023-08-08 17:04:35
 */
public class SpringTest01 {

    public static void main(String[] args) throws DocumentException, IOException {
        SpringIocXml springIocXml = new SpringIocXml();
        UserBean userBean = springIocXml.getBean("userBean");
        System.out.println(userBean);
    }
}

运行结果

Mr. Cappuccino的第59杯咖啡——简单手写SpringIOC框架_第6张图片

基于注解方式

原理

基于反射+工厂模式实现

  1. 判断配置类上是否有@Configuration注解;
  2. 获取配置类中的所有方法,判断方法上是否有@Bean注解,如果有则获取方法的返回值作为实例对象;
  3. 判断配置类上是否有@ComponentScan注解,如果有则扫描指定包下的所有类,并判断类上是否有@Component注解,如果有则通过反射技术初始化对象;
  4. 使用工厂模式管理初始化对象/实例对象;

项目结构

Mr. Cappuccino的第59杯咖啡——简单手写SpringIOC框架_第7张图片

项目代码

pom.xml

<dependency>
    <groupId>cn.hutoolgroupId>
    <artifactId>hutool-allartifactId>
    <version>5.7.7version>
dependency>

ScanBean.java

package com.spring.bean.scan;

import org.springframework.stereotype.Component;

/**
 * @author honey
 * @date 2023-08-09 14:28:33
 */
@Component
public class ScanBean {
}

SpringConfig.java

package com.spring.config;

import com.spring.bean.UserBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author honey
 * @date 2023-08-09 14:26:40
 */
@Configuration
@ComponentScan(value = {"com.spring.bean.scan"})
public class SpringConfig {

    @Bean
    public UserBean userBean() {
        return new UserBean();
    }
}

SpringIocAnnotation.java

package com.spring.ext;

import cn.hutool.core.lang.ClassScanner;
import cn.hutool.core.util.StrUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author honey
 * @date 2023-08-09 14:12:21
 */
public class SpringIocAnnotation {

    private final Object config;
    private final Map<String, Object> beanMap = new ConcurrentHashMap<>();

    public SpringIocAnnotation(Object config) {
        this.config = config;
        init();
    }

    /**
     * 初始化IOC容器
     */
    public void init() {
        // 判断配置类上是否有@Configuration注解
        Configuration configuration = this.config.getClass().getDeclaredAnnotation(Configuration.class);
        if (configuration == null) {
            return;
        }

        // 处理@Bean注解
        Class<?> clazz = config.getClass();
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            // 判断方法上是否有@Bean注解
            Bean bean = method.getDeclaredAnnotation(Bean.class);
            if (bean != null) {
                try {
                    // 获取beanId
                    String[] value = bean.value();
                    String beanId = value.length > 0 ? value[0] : method.getName();
                    // 获取方法的返回值
                    Object object = method.invoke(config);
                    beanMap.put(beanId, object);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        // 处理@Component注解
        ComponentScan componentScan = clazz.getDeclaredAnnotation(ComponentScan.class);
        if (componentScan != null) {
            for (String packageName : componentScan.value()) {
                try {
                    // 扫描指定包下的所有类
                    Set<Class<?>> classes = ClassScanner.scanPackage(packageName);
                    for (Class<?> c : classes) {
                        // 判断类上是否有@Component注解
                        Annotation component = c.getDeclaredAnnotation(Component.class);
                        if (component != null) {
                            try {
                                // 获取beanId
                                String beanId = StrUtil.lowerFirst(c.getSimpleName());
                                // 通过反射技术初始化对象
                                Object beanObject = c.newInstance();
                                beanMap.put(beanId, beanObject);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public <T> T getBean(String name) {
        return (T) beanMap.get(name);
    }
}

SpringTest02.java

package com.spring.test;

import com.spring.bean.UserBean;
import com.spring.bean.scan.ScanBean;
import com.spring.config.SpringConfig;
import com.spring.ext.SpringIocAnnotation;

/**
 * @author honey
 * @date 2023-08-09 14:24:36
 */
public class SpringTest02 {

    public static void main(String[] args) {
        SpringIocAnnotation springIocAnnotation = new SpringIocAnnotation(new SpringConfig());
        UserBean userBean = springIocAnnotation.getBean("userBean");
        System.out.println(userBean);
        ScanBean scanBean = springIocAnnotation.getBean("scanBean");
        System.out.println(scanBean);
    }
}

运行结果

Mr. Cappuccino的第59杯咖啡——简单手写SpringIOC框架_第8张图片

你可能感兴趣的:(Spring,mr,java,开发语言)