实现Spring底层机制(阶段1—编写自己的Spring容器,扫描包,得到bean的Class对象)

环境搭建+抛出问题

1.环境搭建

1.创建maven项目

image-20240221100240215

2.导入依赖
<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>sun-spring</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>sun-spring Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  <!--配置spring的基本包-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.8</version>
    </dependency>
  <!--加入spring开发切面编程需要的包-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.3.8</version>
    </dependency>
  </dependencies>
  <build>
    <finalName>sun-spring</finalName>
  </build>
</project>

3.maven的资源路径问题
类路径

image-20240221102805149

image-20240221103233329

4.IOC演示
1.文件目录

image-20240221103716087

2.UserAction.java
package com.sxs.spring.component;

import org.springframework.stereotype.Component;

/**
 * 这是一个Controller
 *
 * @author 孙显圣
 * @version 1.0
 */
@Component
public class UserAction {
}

3.UserDao.java
package com.sxs.spring.component;

import org.springframework.stereotype.Component;

/**
 * 这是一个dao
 *
 * @author 孙显圣
 * @version 1.0
 */
@Component
public class UserDao {
    public void hi() {
        System.out.println("UserDao-hi()");
    }
}

4.UserService.java
package com.sxs.spring.component;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 这是一个Service
 *
 * @author 孙显圣
 * @version 1.0
 */
@Component
public class UserService {
    //自动装配
    @Autowired
    private UserDao userDao;
    public void m1() {
        userDao.hi();
    }
}

5.AppMain.java
package com.sxs.spring;

import com.sxs.spring.component.UserAction;
import com.sxs.spring.component.UserDao;
import com.sxs.spring.component.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class AppMain {
    public static void main(String[] args) {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        UserAction action1 = ioc.getBean(UserAction.class);
        UserAction action2 = ioc.getBean(UserAction.class);
        System.out.println("action1=" + action1);
        System.out.println("action2=" + action2);
        UserService service = ioc.getBean(UserService.class);
        System.out.println("service=" + service);
        service.m1();
        UserDao userDao = ioc.getBean(UserDao.class);
        System.out.println("userDao=" + userDao);
    }
}

6.beans.xml
<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--配置自动扫描-->
    <context:component-scan base-package="com.sxs.spring.component"/>
</beans>
7.结果

image-20240221104039882

2.抛出问题

1.prototype怎么实现的?

image-20240221105154393

image-20240221105208460

2.Autowired怎么实现的?

image-20240221110223106

3.后置处理器是怎么实现的?
1.使用xml配置后置处理器
<!--配置后置处理器,就是反射创建了一个bean对象,也可以使用component注解创建-->
<bean class="com.sxs.spring.process.MyBeanPostProcessor" id="beanPostProcessor"/>
2.使用注解配置后置处理器
1.配置自动扫描
<!--如果使用注解来配置后置处理器,别忘了在这里配置自动扫描!!!-->
<context:component-scan base-package="com.sxs.spring.process"/>
2.MyBeanPostProcessor.java
package com.sxs.spring.process;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */
//反射创建后置处理器的bean对象
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    /**
     * 在bean的init初始化方法之前执行
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization被调用 " + beanName + "bean=" + bean.getClass());
        return bean;
    }

    /**
     * 在bean的init初始化方法之后执行
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization被调用 " + beanName + "bean=" + bean.getClass());
        //注意:这里如果返回的是空,则还是使用的原来的bean
        return bean;
    }
}

4.Spring AOP是怎么实现的?
1.文件目录

image-20240221144148700

2.SmartAnimalable.java
package com.sxs.spring.aop;

/**
 * @author 孙显圣
 * @version 1.0
 */
public interface SmartAnimalable {
    float getSum(float i, float j);
    float getSub(float i, float j);
}

3.SmartDog.java
package com.sxs.spring.aop;

import org.springframework.stereotype.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Component
public class SmartDog implements SmartAnimalable{
    public float getSum(float i, float j) {
        float res = i + j;
        System.out.println("SmartDog-getSum=" + res);
        return res;
    }

    public float getSub(float i, float j) {
        float res = i - j;
        System.out.println("SmartDog-getSub=" + res);
        return res;
    }
}

4.SmartAnimalAspect.java
package com.sxs.spring.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Component
@Aspect
public class SmartAnimalAspect {
    @Pointcut(value = "execution(public float SmartDog.*(float, float)))")
    public void myPointCut() {
    }


    @Before(value = "myPointCut()")
    public void showBeginLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showBeginLog()[使用的myPointCut()]-方法执行前-日志-方法名-" + signature.getName() + "-参数 "
                + Arrays.asList(joinPoint.getArgs()));
    }


    @AfterReturning(value = "myPointCut()", returning = "res")
    public void showSuccessEndLog(JoinPoint joinPoint, Object res) {
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showSuccessEndLog()-方法执行正常结束-日志-方法名-" + signature.getName() + " 返回的结果是=" + res);
    }


    @AfterThrowing(value = "myPointCut()", throwing = "throwable")
    public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showExceptionLog()-方法执行异常-日志-方法名-" + signature.getName() + " 异常信息=" + throwable);
    }


    @After(value = "myPointCut()")
    public void showFinallyEndLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showFinallyEndLog()-方法最终执行完毕-日志-方法名-" + signature.getName());
    }

}

5.beans.xml
    <!--扫描aop-->
    <context:component-scan base-package="com.sxs.spring.aop"/>
    <!--启动aop注解-->
    <aop:aspectj-autoproxy/>

image-20240221144422676

3.AOP与后置处理器的关系

1.介绍

image-20240221145441554

2.补充说明

这个SmartDog在init之后变成了代理对象,原因是这个类的方法被切面切入了,所以会通过后置处理器返回代理对象

image-20240221150632758

1.Spring整体架构分析 image-20240221153118515

2. 阶段1框架图

image-20240221153328319

3.二说类加载器

image-20240221153659576

image-20240221153636966

4.代码实现

1.环境搭建
1.创建新模块

image-20240221154656270

2.将新模块放在与当前模块并行的位置(location里自己看)

image-20240221160746860

image-20240221160828962

3.成功创建!

image-20240221160903342

4.修改语言级别

image-20240221160949169

5.解决启动错误

这个错误是版本问题

image-20240221172629107

image-20240221172803248

image-20240221173016328

2.文件目录

image-20240221173656748

3.自定义扫描注解,指定要扫描的包ComponentScan.java
package com.sun.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 容器扫描的注解:通过value可以指定要扫描的包
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
    String value() default "";
}

4.自定义Component注解,Component.java
package com.sun.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 组件注解:指定要自动创建bean对象的类,还可以自定义value作为创建bean对象的id
 *
 * @author 孙显圣
 * @version 1.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
    String value() default "";
}

5.三个测试组件
1.Car.java
package com.sun.spring.component;

/**
 * @author 孙显圣
 * @version 1.0
 */
//没有加Component注解
public class Car {
}

2.MonsterDao.java
package com.sun.spring.component;

import com.sun.spring.annotation.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Component(value = "monsterDao")
public class MonsterDao {
}

3.MonsterService.java
package com.sun.spring.component;

import com.sun.spring.annotation.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */

//自定义注解,自动反射创建bean对象,如果指定了value则id为value否则为首字母小写
@Component(value = "monsterService")
public class MonsterService {
}

6.自定义spring容器SunSpringApplicationContext.java
package com.sun.spring.ioc;

import com.sun.spring.annotation.Component;
import com.sun.spring.annotation.ComponentScan;


import java.io.File;
import java.net.URL;

/**
 * 类似于Spring原生的ioc容器
 *
 * @author 孙显圣
 * @version 1.0
 */
public class SunSpringApplicationContext {
    //传进来一个配置类的Class对象
    private Class configClass;

    //构造器,接收配置类的class对象
    public SunSpringApplicationContext(Class configClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        this.configClass = configClass;
        //一、获取要扫描的包
        //1.首先反射获取类的注解信息
        ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
        //2.通过注解来获取要扫描的包的路径
        String path = componentScan.value();
        System.out.println("要扫描的包=" + path);

        //二、得到要扫描包的.class文件对象,从而得到全路径进行反射
        //1.获取类加载器
        ClassLoader classLoader = SunSpringApplicationContext.class.getClassLoader();
        //2.获取要扫描包的真实路径,默认刚开始在根目录下
        path = path.replace(".", "/");
        URL resource = classLoader.getResource(path);
        //3.由该路径创建一个文件对象,可使用resource.getFile()将URL类型转化为String类型
        File file = new File(resource.getFile());
        //4.遍历该文件夹下的所有.class文件对象
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                //反射注入容器
                //1.获取所有文件的绝对路径
                String absolutePath = f.getAbsolutePath();
                //只处理class文件
                if (absolutePath.endsWith(".class")) {
                    //2.分割出类名
                    String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1, absolutePath.indexOf("."));
                    //3.得到全路径
                    String fullPath = path.replace("/", ".") + "." + className;
                    //4.判断是否需要注入容器,查看有没有自定义的注解Component
                    Class<?> aClass = classLoader.loadClass(fullPath);

                    //如果该类使用了注解Component则说明是一个spring bean
                    if (aClass.isAnnotationPresent(Component.class)) {
                        System.out.println("这是一个Spring bean=" + aClass);
                    } else {
                        System.out.println("这不是一个Spring bean=" + aClass);
                    }

                }
            }
        }
    }

    //返回容器中的对象
    public Object getBean(String name) {
        return null;
    }

}

7.自定义配置类(跟自定义扫描注解一起使用,相当于原来的配置文件)SunSpringConfig.java
package com.sun.spring.ioc;

import com.sun.spring.annotation.ComponentScan;

/**
 * 相当于原来的xml配置文件
 * @author 孙显圣
 * @version 1.0
 */
@ComponentScan(value = "com.sun.spring.component") //自定义注解:指定要扫描的包
public class SunSpringConfig {

}
8.启动类AppMain.java
package com.sun.spring;

import com.sun.spring.ioc.SunSpringApplicationContext;
import com.sun.spring.ioc.SunSpringConfig;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class AppMain {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        //
        SunSpringApplicationContext ioc = new SunSpringApplicationContext(SunSpringConfig.class);

    }
}

9.执行结果

image-20240221174318016

5.当前阶段完成的任务

  • 自定义扫描注解和自定义配置类充当配置文件,value存储需要扫描的包
  • 自定义Component注解,用于指定需要自动创建bean对象的类
  • 自定义Spring容器,当容器启动时,创建容器对象传入容器的配置类的Class对象,容器通过构造方法,获取配置类的注解信息,得到要扫描的包的全路径,然后进行一些操作得到这个包下面的所有类的全路径

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/565062.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

隐藏表头和最高层级的复选框

隐藏表头和最高层级的复选框 <!-- 表格 --><el-tableref"tableRef"v-loading"tableLoading"default-expand-allclass"flex-1 !h-auto"row-key"regionId":header-cell-class-name"selectionClass":row-class-name&q…

20240422,C++文件操作

停电一天之后&#xff0c;今天还有什么理由不学习呜呜……还是没怎么学习 一&#xff0c;文件操作 文件操作可以将数据持久化&#xff0c;对文件操作时须包含头文件<fstream> 两种文件类型&#xff1a;文本文件&#xff1a;文件以文本的ASCII码形式存储&#xff1b;二进…

算法导论 总结索引 | 第三部分 第十一章:散列表

1、动态集合结构&#xff0c;它至少要支持 INSERT、SEARCH 和 DELETE字典操作 散列表 是实现字典操作的 一种有效的数据结构。尽管 最坏情况下&#xff0c;散列表中 查找一个元素的时间 与链表中 查找的时间相同&#xff0c;达到了 Θ(n)。在实际应用中&#xff0c;散列表的性…

GLID: Pre-training a Generalist Encoder-Decoder Vision Model

1 研究目的 现在存在的问题是&#xff1a; 目前&#xff0c;尽管自监督预训练方法&#xff08;如Masked Autoencoder&#xff09;在迁移学习中取得了成功&#xff0c;但对于不同的下游任务&#xff0c;仍需要附加任务特定的子架构&#xff0c;这些特定于任务的子架构很复杂&am…

Linux使用Docker部署DashDot访问本地服务器面板

文章目录 1. 本地环境检查1.1 安装docker1.2 下载Dashdot镜像 2. 部署DashDot应用 本篇文章我们将使用Docker在本地部署DashDot服务器仪表盘&#xff0c;并且结合cpolar内网穿透工具可以实现公网实时监测服务器系统、处理器、内存、存储、网络、显卡等&#xff0c;并且拥有API接…

前端开发攻略---拖动归类,将元素拖拽到相应位置

1、演示 2、代码 <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewport" content"widthdevice-…

我在本地部署通义千问Qwen1.5大模型,并实现简单的对话和RAG

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总…

什么是防抖和节流?有什么区别? 如何实现?

防抖&#xff08;Debounce&#xff09;和节流&#xff08;Throttle&#xff09;是两种常用的技术手段&#xff0c;主要用于控制某个函数在一定时间内触发的次数&#xff0c;以减少触发频率&#xff0c;提高性能并避免资源浪费。 防抖&#xff08;Debounce&#xff09;的工作原…

掉落回弹问题(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;float b 100;float sum 0;int i 0;//运算&#xff1b;for (i 1; i < 10; i){//运算&…

【oceanbase】安装ocp,ocp部署oceanbase

https://www.oceanbase.com/docs/common-ocp-1000000000584989 资源 iphostnamecpumem组件192.168.0.71obnode-000-071816oceanbase-ce192.168.0.72obnode-000-072816oceanbase-ce192.168.0.73obnode-000-073816oceanbase-ce192.168.0.74obproxy-000-07424obproxy-ce192.168.0…

【北京迅为】《iTOP-3588开发板系统编程手册》-第16章 串口应用编程

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

291个地级市资源错配指数、劳动和资本相对扭曲指数(2006-2021年)

01、数据介绍 资源错配指数&#xff08;Misallocation Index&#xff09;是一个用于衡量资源配置效率的指标&#xff0c;它衡量的是生产要素的配置是否合理&#xff0c;是否达到了最优的状态。资源错配指数越高&#xff0c;资源的利用效率越低。资源错配指数主要用于衡量各种生…

学习STM32第十七天

备份域详解 一、简介 在参考手册的电源控制章节&#xff0c;提到了备份域&#xff0c;BKPR是在RTC外设中用到&#xff0c;包含20个备份数据寄存器&#xff08;80字节&#xff09;&#xff0c;备份域包括4KB的备份SRAM&#xff0c;以32位、16位或8位模式寻址&#xff0c;在VBAT…

SpringCloud系列(9)--将服务消费者Consumer注册进Eureka Server

前言&#xff1a;上一章节我们介绍了如何将服务提供者注册进Eureka服务里&#xff0c;本章节则介绍如何将服务消费者Consumer注册进Eureka服务里 Eureka架构原理图 1、修改consumer-order80子模块的pom.xml文件&#xff0c;引入Eureka Clinet的依赖&#xff0c;然后reolad一下&…

SVD奇异值分解原理及应用

-------------------------------------------------------------------------------------------------------------------------------- 首先说明&#xff1a;本文的内容来自百家号“人工智能遇见磐创”大佬的整理&#xff0c;感谢原作者&#xff08;本文在原作者的基础上按…

找不到msvcp140dll,无法继续执行代码的详细解决方法

在我们日常使用计算机进行各类工作任务的过程中&#xff0c;时常会遭遇一些突发的技术问题。比如&#xff0c;有时在运行某个重要程序或应用软件时&#xff0c;系统会突然弹出一个令人困扰的错误提示&#xff1a;“电脑提示找不到msvcp140.dll文件&#xff0c;因此无法继续执行…

Mysql基础(二)数据类型和约束

一 数据类型 讲解主要的数据类型,不面面俱到,后续遇到具体问题再查询补充扩展&#xff1a; 知识点的深度和广度以工作为导向 ① int float M : 表示显示宽度&#xff0c;M的取值范围是(0, 255)例如: int(5),当数据宽度小于5位的时候在数字前面需要用字符填满宽度说明&…

双击复制elementui表格某个单元格的数据

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、代码前言 在使用elementui的表格将数据展示出来时,我们想复制该表格区域对应的内容,但因为想复制的列不想太宽而数据太长导致数据省略,无法使用鼠标选择来全部复制到,所以想能不能实现一个双击该内容达到复制效果;…

VSCode 配置 C/C++ 环境

1 安装 VSCode 直接去官网(https://code.visualstudio.com/)下载并安装即可。 2 配置C/C编译环境 方案一 如果是在Windows&#xff0c;需要安装 MingW&#xff0c;可以去官网(https://sourceforge.net/projects/mingw-w64/)下载安装包。 注意安装路径不要出现中文。 打开 w…

声明式事务

文章目录 1.事务分类1.传统方式解决事务2.声明式事务 2.声明式事务案例1.需求分析2.解决方案分析3.数据表创建4.编写GoodsDao.java1.编写配置文件JdbcTemplate_ioc.xml2.单元测试 5.编写GoodsService.java6.配置事务管理器JdbcTemplate_ioc.xml7.进行测试 3.debug事务管理器Dat…