手撕spring框架(2)

相关系列

java中spring底层核心原理解析(1)-CSDN博客

java中spring底层核心原理解析(2)-CSDN博客

手撕spring框架(1)-CSDN博客

手撕spring框架(3)-CSDN博客

手撕spring框架(4)-CSDN博客

       依赖注入原理

        依赖注入(Dependency Injection,简称DI)是一种设计模式,它允许我们解藕组件之间的关系,使得代码更易于测试和维护。在Spring框架中,依赖注入被广泛使用来管理对象(称为beans)及相互之前的依赖关系。Spring容器负责创建对象,配置对象以及管理这些对象的生命周期。 

在手撕spring框架(1)-CSDN博客 中实现核心功能点,今天我们就在此基础上,来完成依赖注入。

 创建Autowired.java

@Autowired是Spring框架提供的一个注解,用于实现依赖注入。我们简化的自定义实现。

功能

  • 自动装配:@Autowired注解可以让Spring容器自动为字段、构造器、setter方法等注入所需的bean。这意味着开发者不需要手动使用new操作符来创建依赖对象的实例,Spring容器会根据类型匹配(默认)或按名称匹配(通过@Qualifier配合使用)来自动提供这些依赖。
  • 默认行为:默认情况下,@Autowired按照类型匹配进行注入。如果存在多个相同类型的bean,Spring会尝试通过名称匹配或者使用@Primary标记的bean来解决歧义。如果没有找到匹配项,且没有配置为可选注入(通过@Autowired(required = false)),Spring将抛出异常。
  • 位置
    • 字段:直接标注在字段上,是最常见的使用方式。
    • 构造器:可以用来标识一个构造器来进行依赖注入,特别是当类有多个构造器或者依赖是必须的时候非常有用。
    • setter方法:适用于需要在对象创建之后设置依赖的情况。
  • 可选性:通过required属性可以声明依赖是否是必须的,默认为true表示必须注入,设为false则表示如果没有匹配的bean,也不会抛出异常。 
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {String value() default "";
}

字段注入

修改原有的UserService.java文件

package com.dzend.service;import com.spring.Autowired;
import com.spring.Component;@Component(value = "userService")
public class UserService  {@Autowiredprivate OrderService orderService;public OrderService getOrderService() {return orderService;}}

调用DzendApplicationContext中文件createBean方法

则整个文件如下:

package com.spring;import java.beans.Introspector;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class DzendApplicationContext {private Class<?> configClass;private Map<String,BeanDefinition> beanDefinitionMap= new HashMap<>();private Map<String, Object> singletonObjects=new HashMap<>();private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();public DzendApplicationContext(Class configClass)   {this.configClass=configClass;scan(configClass);}private void scan(Class configClass) {if(configClass.isAnnotationPresent(ComponentScan.class)){ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);String path = componentScan.value();path = path.replace(".","/");ClassLoader classLoader = DzendApplicationContext.class.getClassLoader();URL resource = classLoader.getResource(path);try {path = URLDecoder.decode(path, "UTF-8");} catch (UnsupportedEncodingException e) {throw new RuntimeException(e);}File file = null;try {file = new File(  URLDecoder.decode(resource.getFile(), "UTF-8"));} catch (UnsupportedEncodingException e) {throw new RuntimeException(e);}if(file.isDirectory()){for (File f : file.listFiles()) {String absolutePath = f.getAbsolutePath();absolutePath = absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class"));absolutePath=absolutePath.replace("\\",".");try {Class<?>  clazz = classLoader.loadClass(absolutePath);if (clazz.isAnnotationPresent(Component.class)) {Component componentAnnotaion = clazz.getAnnotation(Component.class);String beanName= componentAnnotaion.value();if("".equals(beanName)){beanName = Introspector.decapitalize(clazz.getSimpleName());}BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setType(clazz);if (clazz.isAnnotationPresent(Scope.class)) {Scope scopeAnnotation = clazz.getAnnotation(Scope.class);String value = scopeAnnotation.value();beanDefinition.setScope(value);}else{beanDefinition.setScope("singleton");}beanDefinitionMap.put(beanName,beanDefinition);}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (NoSuchMethodException e) {throw new RuntimeException(e);}}}}}public Object getBean(String beanName){if(!beanDefinitionMap.containsKey(beanName)){throw new NullPointerException();}BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);if(beanDefinition.getScope().equals("singleton")){Object singletonObject = singletonObjects.get(beanName);if(singletonObject == null){singletonObject = createBean(beanName,beanDefinition);singletonObjects.put(beanName,singletonObject);}return singletonObject;}else{//原型Object prototypeBean = createBean(beanName, beanDefinition);return prototypeBean;}}private Object createBean(String beanName, BeanDefinition beanDefinition) {Class clazz = beanDefinition.getType();Object instance = null;try {instance = clazz.getConstructor().newInstance();for (Field field : clazz.getDeclaredFields()) {if(field.isAnnotationPresent(Autowired.class)){field.setAccessible(true);field.set(instance,getBean(field.getName()));}}} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (NoSuchMethodException e) {throw new RuntimeException(e);}return instance;}
}

最后修改Test.java中的main方法

package com.dzend;import com.dzend.service.UserService;
import com.spring.DzendApplicationContext;public class Test {public static void main(String[] args) {//扫描   ->创建对象DzendApplicationContext applicationContext = new DzendApplicationContext(AppConfig.class);UserService userService = (UserService) applicationContext.getBean("userService");userService.getOrderService().test();}
}

执行结果 

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

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

相关文章

用龙梦迷你电脑福珑2.0做web服务器

用龙梦迷你电脑福珑2.0上做web服务器是可行的。已将一个网站源码放到该电脑&#xff0c;在局域网里可以访问网站网页。另外通过在同一局域网内的一台windows10电脑上安装花生壳软件&#xff0c;也可以在外网访问该内网服务器网站网页。该电脑的操作系统属于LAMP。在该电脑上安装…

Qt Creator导入第三方so库和jar包——Qt For Android

前言 之前了解了在Android Studio下导入so库和jar包&#xff0c;现在实现如何在Qt上导入so库和jar包。 实现 下面是我安卓开发&#xff08;需调用安卓接口的代码&#xff09;的目录&#xff08;图1&#xff09;&#xff0c;此目录结构和原生态环境&#xff08;Android Studi…

详细分析Java中的脱敏注解(附Demo)

目录 前言1. 基本知识2. 核心逻辑3. Demo4. 模版 前言 对于隐私信息&#xff0c;需要做特殊处理&#xff0c;比如身份证或者手机号等 对于Java的相关知识推荐阅读&#xff1a;java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09; 1. 基本知…

软件定义汽车落地的五大关键要素

1、架构升级 1.1 软件架构&#xff1a;分层解耦、服务化、API 接口标准化 随着企业向软件定义汽车开发方法的转变&#xff0c;软件架构也需要同步进行升级&#xff0c;引入面向服务的架构&#xff08;Service-Oriented Architecture&#xff0c;简称 SOA&#xff09;方法论。…

LeetCode刷题之买卖股票的最佳时机

文章目录 1. 买卖股票的最佳时机1.1 描述1.2 分析1.3 解答 2.买卖股票的最佳时机II2.1 描述2.2 分析2.3 解答2.4 拓展2.5 拓展二 1. 买卖股票的最佳时机 题121 买卖股票的最佳时机 1.1 描述 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 …

【Android学习】按钮监听代码

1. 简介 Button组件是Android中常用的组件&#xff0c;Button常需要和View.OnClickListener配合使用。这里记录下Button配置监听的过程。 2. 代码分析 2.1 Layout的XML代码 <Buttonandroid:id"id/btn"android:layout_width"match_parent"android:lay…

ThreeJS:响应式画布与全屏控制

响应式画布 响应式画布&#xff1a;在用户缩放浏览器窗口时&#xff0c;为便于动态更新画布尺寸与宽高比例&#xff0c;需要通过监听resize事件&#xff0c;来实现响应式画布。 window.onresize function () {//TODO:重置渲染器宽高比renderer.setSize(window.innerWidth, wi…

图文、视频处理等自媒体工具

文章目录 文本转文本图片canva同类竞品文本生成PDF,PDF再导出为图片贴入笔记类应用(如小米笔记App)中然后选择以图片形式分享UU在线工具的文字生成长图醒图App其他竞品文本转配音视频剪映将文本生成一段朗读该文本的配音视频(需要自行切割多段内容并分配时间轴)腾讯智影将…

为人处事电影解说,全新升级瀚海跑道一分钟一条视频,全平台可推广,轻轻松松日入1000

自古以来&#xff0c;我国流行的一种现象是&#xff0c;大多数人都会与领导或上司打交道。由于某些话题不宜公开讨论&#xff0c;因此出现了许多含蓄的表达方式。随着年龄的增长&#xff0c;人们的态度也发生了变化&#xff0c;从最初的轻视到现在的重视。 下 载 地 址&#…

VG做mirror引起的块偏移

事件起因 Oracle10.2环境 Aix操作系统使用aix的lvm技术。制作vg的mirror。以此来替换掉老的存储。 做mirror前&#xff0c;数据库已完全关闭 故障现象 在启动数据库时&#xff0c;发现IO错误。该系统的spfile&#xff0c;ctl&#xff0c;dbf均是用lv做的裸设备。其中dbf是使…

WebGL是啥

WebGL&#xff08;全写为Web Graphics Library&#xff09;是一种3D绘图协议&#xff0c;这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起&#xff0c;通过增加OpenGL ES 2.0的一个JavaScript绑定&#xff0c;WebGL可以为HTML5 Canvas提供硬件3D加速渲染。这样&…

【重学C语言】十二、指针高级-函数指针

【重学C语言】十二、指针高级-函数指针 函数指针小案例回调函数如何看懂复杂的指针右左法则案例走起1.int (\*p[5])(int\*)2. int (\*fun)(int \*p,int (\*pf)(int \*))3. int (\*(\*fun)[5])(int \*p)4. int (\*(\*fun)(int \*p))[5]5. int(\*(\*fun())())()函数指针 函数指针…

cmake的使用方法: 编译生成库文件

一. 简介 前面文章学习了针对单个 .c文件&#xff0c;cmake 工具是如何编译的&#xff1f; 针对包含多个 .c文件&#xff0c;cmake工具又是如何编译的&#xff1f;文章如下&#xff1a; cmake的使用方法: 单个源文件的编译-CSDN博客 cmake的使用方法: 多个源文件的编译-CS…

Java入门-final关键字

final关键字 修饰基本类型 变量为只读&#xff0c;不能修改变量的内容。 final int SIZE 3;修饰引用类型 引用的对象不能改变&#xff0c;但是对象的内容可以修改。 final Car c new Car( );c.setColor("红色");修饰类的属性 类的属性不能被修改。 第一种方式&…

Linux 进程间通信之命名管道

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;Linux知识分享⏪   &#x1f69a;代码仓库:Linux代码练习&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Linux知识   &#x1f51d; 目录 前言 命名管道 创建一个命名管道 …

Pandas库的基本使用

什么是Pandas? 一个开源的Python类库&#xff1a;用于数据分析、数据处理、数据可视化 高性能容易使用的数据结构容易使用的数据分析工具 很方便和其它类库一起使用&#xff1a; numpy&#xff1a;用于数学计算scikit-learn&#xff1a;用于机器学习 怎样下载安装Pandas …

Flask后端之建立模型类间的外键联系

1、模型类代码&#xff1a; 定义了三个模型类&#xff1a;User、Goods 和 Sign&#xff1a; class User(db.Model):__tablename__ userid db.Column(db.Integer, primary_keyTrue)name db.Column(db.String(100), nullableFalse)email db.Column(db.String(100), uniqueT…

商城数据库(36 37 38 39 40)

36 CREATE TABLE sxh_log_operates (operateId int(11) NOT NULL AUTO_INCREMENT COMMENT 自增ID,staffId int(11) NOT NULL DEFAULT 0 COMMENT 职员ID,operateTime datetime NOT NULL COMMENT 操作时间,menuId int(11) NOT NULL COMMENT 所属菜单ID,operateDesc varchar(255)…

UI自动化与接口自动化比较

UI自动化与接口自动化优比较&#xff1a; 1、执行效率 接口自动化执行效率比UI自动化执行效率更高(调用接口比打开页面要快很多) 2、稳定性 UI自动化容易受设备卡顿&#xff0c;系统弹框等因素影响而导致脚本执行失败、接口自动化不存在此问题&#xff0c;因此接口自动化测试…

ES常用查询方式

Elasticsearch&#xff08;ES&#xff09;作为功能强大的检索引擎&#xff0c;提供了多种查询方式&#xff0c;在不同的场景下需要选择合适的查询方式以取得最佳查询效果。 ES常用查询方式 方式说明Match Query&#xff08;匹配查询&#xff09;根据字段的内容进行全文匹配查…