手写Spring之V2版本

本文旨在通过手写Spring V2版本,深入理解Spring的IoC、DI、MVC和AOP等核心机制。首先介绍了实现目标和基本思路,然后详细讲解了从配置文件解析到自定义注解,再到IoC、DI、MVC和AOP的组件实现,最后展示了具体的代码示例和Demo应用。
摘要由CSDN通过智能技术生成

1.目标

在手写最基础的V1版本Spring之后,再次学习Spring中的核心源码,提取出Spring中核心的IoC、DI、MVC、AOP各组件的的分工,自己用代码手写完成这些组件。

2.基本思路

IoC,DI思路总结:

1.调用Servlet init()方法,创建ApplicationContext
2.读取配置文件(peoperties、xml、yml)
3.BeanDefinitionReader解析配置文件,扫描相关的类,封装成BeanDefinition保存到了内存中
4.在ApplicationContext.getBean后,初始化IOC容器,并且实例化对象,封装成BeanWrapper。
5.完成DI注入
在这里插入图片描述

MVC思路总结

1.初始化九大组件之HandlerMapping:读取所有的RequestMapping中的url结合instance、Method缓存到HandlerMapping
2.初始化九大组件之HandlerAdapter:为每个HandlerMapping创建一个HandlerAdapter(目前其实没有适配改变内容)并缓存
3.初始化九大组件之ViewResolver:读取配置文件的模板根目录。
在这里插入图片描述

AOP思路总结

1.在IoC初始化所有类时,创建GPAdvisedSupport,读取AopConfig配置文件。
2.GPAdvisedSupport中解析配置文件,使用正则匹配,创建method - Advices对应缓存。
3.,匹配aop类,创建Proxy类替代原类初始化,在Proxy类中,读取method - Advices缓存,调用对应的advice方法。
在这里插入图片描述

3.源码实现

PS.说明

源码实现部分由于在编写代码时,可能在同一个类中不断新增一些代码,所以并不是以编写顺序排序。

3.1.自定义配置 application.properties 文件

为了解析方便,我们用application.properties来代替application.xml文 件 ,具体配置内容如下:

#托管的类扫描包路径#
scanPackage=com.gupaoedu.vip.demo

templateRoot=layouts

#切面表达式expression#
pointCut=public .* com.gupaoedu.vip.demo.service..*Service..*(.*)
#切面类
aspectClass=com.gupaoedu.vip.demo.aspect.LogAspect
#前置通知回调方法
aspectBefore=before
#后置通知回调方法
aspectAfter=after
#异常通知回调方法
aspectAfterThrow=afterThrowing
#异常类型捕获
aspectAfterThrowingName=java.lang.Exception

3.2.配置web.xml文件

大家都知道,所有依赖于web容器的项目,都是从读取web.xml文件开始的。我们先配置好web.xml
中的内容。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
	version="2.4">
	<display-name>Gupao Web Application</display-name>
	<servlet>
		<servlet-name>gpmvc</servlet-name>
		<servlet-class>com.gupaoedu.vip.spring.framework.webmvc.servlet.GPDispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>application.properties</param-value>
		</init-param>

		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>gpmvc</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
</web-app>

其中GPDispatcherServlet是有自己模拟Spring实现的核心功能类。

3.3自定义 Annotation

3.3.1 @GPService 注解:

@Target({
   ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GPService {
   
    String value() default "";
}

3.3.2 @GPAutowired 注 解 :

@Target({
   ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GPAutowired {
   
    String value() default "";
}

3.3.3 @GPController 注 解 :

@Target({
   ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GPController {
   
    String value() default "";
}

3.3.4 @GPRequestMapping 注 解 :

@Target({
   ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GPRequestMapping {
   
    String value() default "";
}

3.3.5 @GPRequestParam 注 解 :

@Target({
   ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GPRequestParam {
   
    String value() default "";
}

3.4 IoC、DI部分

3.4.1 GPBeanDefinition

public class GPBeanDefinition {
   
    private String factoryBeanName;
    private String beanClassName;

    public String getFactoryBeanName() {
   
        return factoryBeanName;
    }

    public void setFactoryBeanName(String factoryBeanName) {
   
        this.factoryBeanName = factoryBeanName;
    }

    public String getBeanClassName() {
   
        return beanClassName;
    }

    public void setBeanClassName(String beanClassName) {
   
        this.beanClassName = beanClassName;
    }
}

3.4.2 GPBeanDefinitionReader

public class GPBeanDefinitionReader {
   

    //保存扫描的结果
    private List<String> regitryBeanClasses = new ArrayList<String>();
    private Properties contextConfig = new Properties();

    public GPBeanDefinitionReader(String... configLocations) {
   
        doLoadConfig(configLocations[0]);

        //扫描配置文件中的配置的相关的类
        doScanner(contextConfig.getProperty("scanPackage"));
    }

    public Properties getConfig(){
   
        return this.contextConfig;
    }

    public List<GPBeanDefinition> loadBeanDefinitions() {
   
        List<GPBeanDefinition> result = new ArrayList<GPBeanDefinition>();
        try {
   
            for (String className : regitryBeanClasses) {
   
                Class<?> beanClass = Class.forName(className);
                if(beanClass.isInterface()){
   continue;}
                //保存类对应的ClassName(全类名)
                //还有beanName
                //1、默认是类名首字母小写
                result.add(doCreateBeanDefinition(toLowerFirstCase(beanClass.getSimpleName()), beanClass.getName()));
                //2、自定义
                //3、接口注入
                for (Class<?> i : beanClass.getInterfaces()) {
   
                    result.add(doCreateBeanDefinition(i.getName(),beanClass.getName()));
                }

            }
        }catch (Exception e){
   
            e.printStackTrace();
        }

        return result;
    }

    private GPBeanDefinition doCreateBeanDefinition(String beanName, String beanClassName) {
   
        GPBeanDefinition beanDefinition = new GPBeanDefinition();
        beanDefinition.setFactoryBeanName(beanName);
        beanDefinition.setBeanClassName(beanClassName);
        return beanDefinition;
    }


    private void doLoadConfig(String contextConfigLocation) {
   
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation.replaceAll("classpath:",""));
        try {
   
            contextConfig.load(is);
        } catch (IOException e) {
   
            e.printStackTrace();
        }finally {
   
            if(null != is){
   
                try {
   
                    is.close();
                } catch (IOException e) {
   
                    e.printStackTrace();
                }
            }
        }
    }

    private void doScanner(String scanPackage) {
   
        //jar 、 war 、zip 、rar
        URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.","/"));
        File classPath = new File(url.getFile());

        //当成是一个ClassPath文件夹
        for (File file : classPath.listFiles()) {
   
            if(file.isDirectory()){
   
                doScanner(scanPackage + "." + file.getName());
            }else {
   
                if(!file.getName().endsWith(".class")){
   continue;}
                //全类名 = 包名.类名
                String className = (scanPackage + "." + file.getName().replace(".class", ""));
                //Class.forName(className);
                regitryBeanClasses.add(className);
            }
        }
    }

    //自己写,自己用
    private String toLowerFirstCase(String simpleName) {
   
        char [] chars = simpleName.toCharArray();
//        if(chars[0] > )
        chars[0] += 32;
        return String.valueOf(chars)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
智慧校园2.0是高校信息化建设的新阶段,它面对着外部环境变化和内生动力的双重影响。国家战略要求和信息技术的快速发展,如云计算、大数据、物联网等,为智慧校园建设提供了机遇,同时也带来了挑战。智慧校园2.0强调以服务至上的办学理念,推动了教育模式的创新,并对传统人才培养模式产生了重大影响。 智慧校园建设的解决之道是构建一个开放、共享的信息化生态系统,利用互联网思维,打造柔性灵活的基础设施和强大的基础服务能力。这种生态系统支持快速迭代的开发和持续运营交付能力,同时注重用户体验,推动服务创新和管理变革。智慧校园的核心思想是“大平台+微应用+开放生态”,通过解耦、重构和统一运维监控,实现服务复用和深度融合,促进业务的快速迭代和自我演化。 智慧校园的总体框架包括多端协同,即“端”,它强调以人为中心,全面感知和捕获行为数据。这涉及到智能感知设备、超级APP、校园融合门户等,实现一“码”或“脸”通行,提供线上线下服务端的无缝连接。此外,中台战略是智慧校园建设的关键,包括业务中台和数据中台,它们支持教育资源域、教学服务域等多个领域,实现业务的深度融合和数据的全面治理。 在技术层面,智慧校园的建设需要分期进行,逐步解耦应用,优先发展轻量级应用,并逐步覆盖更多业务场景。技术升级路径包括业务数据化、数据业务化、校园设施智联化等,利用IoT/5G等技术实现设备的泛在互联,并通过人工智能与物联网技术的结合,建设智联网。这将有助于实现线上线下一网通办,提升校园安全和学习生活体验,同时支持人才培养改革和后勤管理的精细化。 智慧校园的建设不仅仅是技术的升级,更是对教育模式和管理方式的全面革新。通过构建开放、共享的信息化生态系统,智慧校园能够更好地适应快速变化的教育需求,提供更加个性化和高效的服务,推动教育创新和人才培养的高质量发展。
### 回答1: Spring Framework是一个开源的Java平台,它提供了一组全面的工具来支持Java应用程序开发。它主要包括IoC容器、AOP框架、事务管理、MVC框架、DAO框架、连接池等。它可以帮助程序员更好地组织代码,减少重复性工作,提高代码质量。手写Spring框架需要对Java编程和设计模式有较深的了解,并对Spring框架的源码有着深入的研究。 ### 回答2: Spring框架是一个开源的Java平台,用于构建企业级应用程序。它提供了一种全面的编程和配置模型,用于开发基于Java的应用程序和服务。手写Spring框架意味着从头开始实现Spring的核心功能。 手写Spring框架的基本步骤包括: 1. 创建一个核心容器类,用于管理应用程序中的Bean对象。这个容器类需要提供注册、获取和销毁Bean的功能。 2. 定义一个Bean注解,用于标识哪些类应该被容器所管理。 3. 创建一个Bean定义类,用于存储每个Bean的元数据信息,包括类名、作用域和依赖关系等。 4. 实现依赖注入功能,通过读取Bean定义中的依赖关系,将相关的Bean对象注入到目标Bean中。 5. 提供AOP(面向切面编程)功能,允许开发者在应用程序的特定点进行横切关注点的处理。 6. 实现声明式事务管理功能,使用注解或XML配置方式来处理数据库事务。 7. 提供对不同数据访问技术(如JDBC、ORM框架、NoSQL等)的支持,通过集成相应的库来简化数据访问代码。 8. 增加对Web开发的支持,如处理请求、渲染视图等。 手写Spring框架需要具备对Java语言的深入了解,熟悉反射、代理、设计模式等概念和技术。还需要对依赖注入、AOP、事务管理、Web开发等方面有一定的理解。实现一个完整的Spring框架是一个庞大而复杂的任务,需要经过反复的设计、开发和测试。通过手写Spring框架,可以更深入地理解Spring的原理和内部机制,提高对框架的使用和调试能力。 ### 回答3: 手写Spring框架是一个相当复杂的任务,但我可以简要介绍手写Spring框架的一些关键步骤和组成部分。 1. 依赖注入:Spring框架的核心概念之一是依赖注入。我们需要编写一个容器,负责管理和维护各个对象之间的依赖关系。可以使用反射机制来实现依赖注入。 2. 控制反转:Spring框架通过控制反转(IoC)来管理对象的创建和生命周期。我们需要编写一个BeanFactory,负责加载和实例化对象,并将依赖注入到相应的对象中。 3. 配置文件:手写Spring框架也需要一个配置文件,用于定义对象的依赖关系和属性。我们可以使用XML、注解或者JavaConfig等方式来定义配置文件。 4. AOP支持:Spring框架提供了面向切面编程(AOP)的支持,可以通过编写切面和通知来实现横切关注点的统一处理。我们需要实现一个AOP框架,用于拦截和处理切面逻辑。 5. MVC模式:Spring框架也提供了一个MVC框架,用于处理Web应用程序的请求和响应。我们需要编写一个DispatcherServlet,负责将请求分发给相应的控制器,并处理模型和视图的交互。 6. 整合其他技术:Spring框架还可以与其他技术进行整合,例如数据库访问、事务管理、安全性控制等。我们需要编写相应的模块,将这些技术与Spring框架集成起来。 虽然这只是一个简要的介绍,手写Spring框架是一个非常庞大的工程,需要深入理解Spring的原理和设计思想,并具备扎实的Java编程能力。但通过手写Spring框架,我们可以更好地掌握Spring的核心概念和原理,并加深对框架的理解。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值