实现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 {//自动装配@Autowiredprivate 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());//注意:这里如果返回的是空,则还是使用的原来的beanreturn 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.判断是否需要注入容器,查看有没有自定义的注解ComponentClass<?> aClass = classLoader.loadClass(fullPath);//如果该类使用了注解Component则说明是一个spring beanif (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对象,容器通过构造方法,获取配置类的注解信息,得到要扫描的包的全路径,然后进行一些操作得到这个包下面的所有类的全路径

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录第43天|1049.最后一块石头的重量II 494. 目标和

1049.最后一块石头的重量II 1049. 最后一块石头的重量 II - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 动态规划之背包问题&#xff0c;这个背包最多能装多少&#xff1f;LeetCode&#xff1a;1049.最后一块石头的重量II_哔哩哔哩_bilibili 有…

AI-数学-高中-39空间向量-2空间向量法(法向量)

原作者视频&#xff1a;【空间向量】【一数辞典】2空间向量法&#xff08;重要&#xff09;_哔哩哔哩_bilibili 法向量&#xff08;高中阶段所有与面的关系&#xff0c;都可以通过法向量去证明和解答&#xff09;&#xff1a; 是空间解析几何的一个概念&#xff0c;垂直于平面…

京东商品详情数据采集API接口|附京东商品数据返回PHP多语言高并发

京东获得JD商品详情 API 返回值说明 item_get-获得JD商品详情 API测试 注册开通 jd.item_get 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址…

AI时代,操作系统交互的革命性变革

AI时代对操作系统交互的影响 对于2024年的智能手机厂商们来说&#xff0c;在冲击高端市场的路上有一场绝对输不起的硬仗&#xff0c;那就是AI大模型的落地之战。 OpenAI的ChatGPT引爆了全球AIGC&#xff08;生成式人工智能&#xff09;热潮&#xff0c;短短一年时间里&#xff…

新手小白,在数学建模的过程中应该怎么分工?

大家知道&#xff0c;数学建模竞赛是需要一个团队的三个人在三天或四天的时间内&#xff0c;完成模型建立&#xff0c;编程实现和论文写作的任务&#xff0c;对许多第一次参加建模或者建模经验比较欠缺的团队来说&#xff0c;是时间紧任务重的&#xff0c;那么怎么办呢&#xf…

Java学习笔记26(枚举和注解)

1.枚举和注解 1.1 枚举 ​ 1.枚举(enumeration) ​ 2.枚举是一组常量的集合 ​ 3.枚举属于一种特殊的类&#xff0c;里面只包含一组有限的特定的对象 1.枚举应用案例 ​ 1.不需要提供setXxx方法&#xff0c;因为枚举对象值通常为只读 ​ 2.对枚举对象/属性使用final st…

C语言实现三子棋游戏(可以改变为四子棋或者多子棋版)

目录 游戏介绍 游戏框架 游戏基本逻辑的介绍 游戏具体功能实现 初始化棋盘 打印棋盘 玩家下棋 电脑下棋 判断输赢 行和列&#xff1a; 对角线&#xff1a; 平局&#xff1a; 游戏继续&#xff1a; 游戏完整代码 test.c game.c game.h 游戏介绍 三子棋游戏或者…

浏览器不兼容的问题和通用解决方案

大家好&#xff0c;我是咕噜铁蛋&#xff0c;今天我想和大家聊聊一个在我们日常上网过程中经常遇到的问题——浏览器不兼容。这个问题看似微小&#xff0c;但却常常让我们在浏览网页、使用在线应用时感到困扰。接下来&#xff0c;我将详细分析浏览器不兼容的原因&#xff0c;并…

[lesson48]同名覆盖引发的问题

同名覆盖引发的问题 父子间的赋值兼容 子类对象可以当做父类对象使用(兼容性) 子类对象可以直接赋值给父类对象(<font color>兼容性)子类对象可以直接初始化父类对象父类指针可以直接指向子类对象父类引用可以直接引用子类对象 当使用父类指针(引用)指向子类对象时 子类…

30 消息队列

原理 操作系统可以通过页表映射在共享区创建一块共享内存&#xff0c;也可以申请一个队列。A进程和B进程可以向这个队列发送数据块&#xff0c;两个进程接收数据块来通信 函数 申请数据块 参数中的key来自于ftok函数 删除消息队列 同样消息队列也有数据结构管理&#xff…

数值分析复习:Richardson外推和Romberg算法

文章目录 Richardson外推Romberg&#xff08;龙贝格&#xff09;算法 本篇文章适合个人复习翻阅&#xff0c;不建议新手入门使用 本专栏&#xff1a;数值分析复习 的前置知识主要有&#xff1a;数学分析、高等代数、泛函分析 本节继续考虑数值积分问题 Richardson外推 命题&a…

解决在linux中执行tailscale up却不弹出验证网址【Tailscale】【Linux】

文章目录 问题解决提醒 问题 最近有远程办公需求&#xff0c;需要连接内网服务器&#xff0c;又不太想用todesk&#xff0c;于是找到一个安全免费可用的Tailscale Best VPN Service for Secure Networks&#xff0c;在windows中顺利注册账号后&#xff0c;登陆了我的windows …

上位机图像处理和嵌入式模块部署(树莓派4b进行驱动的编写)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 树莓派4b上面还支持驱动代码的编写&#xff0c;这是我没有想到的。这里驱动&#xff0c;更多的是一种框架的编写&#xff0c;不一定是编写真正的驱…

20240422,C++文件操作

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

【Vue3】$subscribe订阅与反应

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

超越OpenAI,谷歌重磅发布从大模型蒸馏的编码器Gecko

引言&#xff1a;介绍文本嵌入模型的重要性和挑战 文本嵌入模型在自然语言处理&#xff08;NLP&#xff09;领域扮演着至关重要的角色。它们将文本转换为密集的向量表示&#xff0c;使得语义相似的文本在嵌入空间中彼此靠近。这些嵌入被广泛应用于各种下游任务&#xff0c;包括…

VideoComposer: Compositional Video Synthesis with Motion Controllability

decompose videos into three distinct types of conditions: textual conditions, spatial conditions, temperal conditions 条件的内容&#xff1a; a. textual condition: coarse grained visual content and motions, 使用openclip vit-H/14的text encoder b. spatial co…

Splashtop 将在 NAB 展会上推出音视频剪辑增强功能

加利福尼亚州拉斯维加斯 Splashtop 在简化随处办公远程解决方案领域处于领先地位&#xff0c;在今年举行的 NAB 展会上将推出 Enterprise 解决方案的高级性能功能&#xff0c;均面向广播和媒体工作者而设计。 Splashtop Enterprise 经过优化&#xff0c;可为执行视频剪辑、唇…

Excel文件解析--超大Excel文件读写

使用POI写入 当我们想在Excel文件中写入100w条数据时&#xff0c;我们用普通的XSSFWorkbook对象写入时会发现&#xff0c;只有在将100w条数据全部加载入内存后才会用write()方法统一写入&#xff0c;这样效率很低&#xff0c;所以我们引入了SXSSFWorkbook进行超大Excel文件的读…

java开发之路——node.js安装

1. 安装node.js 最新Node.js安装详细教程及node.js配置 (1)默认的全局的安装路径和缓存路径 npm安装模块或库(可以统称为包)常用的两种命令形式&#xff1a; 本地安装(local)&#xff1a;npm install 名称全局安装(global)&#xff1a;npm install 名称 -g本地安装和全局安装…