IoC DI

Spring 的两大核心思想 : IoC 和 AOP

我们要将对象的控制权交给Spring ,我们就需要告诉 Spring 哪些对象是需要帮我们进行创建的,这里有两类注解可以实现 :

类注解(@Controller @Service @Repository @Component @Configuration)和方法注解(@Bean)

这五大注解都表示把这个对象交给 Spring 进行管理和创建

五大注解和实际项目开发的关系 : 

@Controller @Service @Repository 和三层架构有关系

Controller : 接收请求并返回响应

Service : 接收完请求具体要做些什么样的事情,真正业务的逻辑处理是什么都是 Service 做的

Dao : 对数据进行处理

@Component 存储组件相关,@Configuration 存储配置相关

我们查看五个类注解的原码 : @Controller @Service @Repository @Component @Configuration

这四个注解都是基于 @Component 实现的,可以认为是 @Component 的衍生类

但是是不是说我们所有程序都使用 @Component 就行呢,那是当然不行的,那搞这么多注解就没意义了

我们用代码尝试一下能否使用 @Service 代替 @Controller 呢?@Controller 是接收请求返回响应,看看换成 @Service 是否还能接收请求返回响应

package com.example.ioc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@ResponseBody
public class TestController {
    @RequestMapping("/test")
    public String test(){
        return "测试Controller 和其他注解的区别";
    }
}

现在我们把 @Controller 换成 @Service ,我们发现报错了

这是因为 Spring 对 Controller 进行了一些处理,我们想接收请求就只能使用 Controller ,就是说Controller必须作为我们程序的第一关,这是规范,不能使用其他注解

那么 @Service 这些可以使用 @Component 来代替呢? 这是可以的,但是并不建议

但是明明 @Service 和 @Controller 的原码明明差不多,为什么应用上有区别呢?这是因为原码只是注解的声明,只是声明了一个注解,但是 Spring 对于这个注解还会赋予一些别的功能,这些功能在 Spring 的原码里面

五大注解只能加在类上,并且只能加在自己的代码上,如果我引入了一个 jar包,也希望交给Spring 管理,这是没有办法加五大注解的,这时候就要使用 @Bean

@Bean 是方法注解 , @Bean 需要搭配五大注解来使用

使用 @Bean 注解时,bean 的名称是方法名

五大注解是,bean 的名称是类名的首字母转为小写,如果前两个字母都为大写,bean 的名称就是类名

还有另一个场景可以使用 @Bean ,对于一个类,我们需要定义多个对象时,比如数据库操作,定义多个数据源

因为当我们用别的注解的时候,拿到的是同一个数据,地址都一样,我们拿 @Configuration 举例

package com.example.ioc.config;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {
    public void doConfig(){
        System.out.println("do configurarion...");
    }
}
        UserConfig userConfig = context.getBean(UserConfig.class);
        userConfig.doConfig();
        System.out.println("userConfig:"+userConfig);

        UserConfig userConfig1 = context.getBean(UserConfig.class);
        System.out.println("userConfig:"+userConfig1);
        System.out.println("userConfig == userConfig1"+(userConfig==userConfig1));
    

 我们发现,两个数据的地址是完全相同的,它们是否相等的判定返回也是 true 

接下来我们用 @Bean 试试看

package com.example.ioc.config;
import lombok.Data;

@Data
//假如这是第三方包下的一个类
//现在我在我的项目中用到了 UserInfo,并且我需要用它定义多个对象
public class UserInfo {
    private Integer id;
    private String name;
    private Integer age;
}
package com.example.ioc.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfig {
    @Bean
    public UserInfo userInfo(){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName("zhangsan");
        userInfo.setAge(12);
        return userInfo;
    }
    @Bean
    public UserInfo userInfo2(){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(2);
        userInfo.setName("wangwu");
        userInfo.setAge(13);
        return userInfo;
    }
}
package com.example.ioc;

import com.example.ioc.component.UserComponent;
import com.example.ioc.config.UserConfig;
import com.example.ioc.config.UserInfo;
import com.example.ioc.controller.UserController;
import com.example.ioc.repo.UserRepository;
import com.example.ioc.service.UserService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        //Spring 上下文
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        //返回的就是 Spring 的运行环境

       
        //@Bean演示
        UserInfo userInfo = (UserInfo) context.getBean("userInfo");
        System.out.println(userInfo);

        UserInfo userInfo2 = (UserInfo) context.getBean("userInfo2");
        System.out.println(userInfo2);

    }

}

这样就能返回两个不一样的内容了 

当一个类型存在多个 bean 时,我们就不能使用类型来获取对象了,就要使用名称进行获取了,或者是名称+类型进行获取

 UserInfo userInfo1 = context.getBean("userInfo",UserInfo.class);
        System.out.println(userInfo1);

这样依然可以拿到 

当我们想进行传参,代码改为 :

package com.example.ioc.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfig {
    @Bean
    public String name(){
        return "wangwu";
    }
    @Bean
    public UserInfo userInfo(String name){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(12);
        return userInfo;
    }
   
}

运行结果如下 

上面代码我把 public String name 改为 public String name2 依然可以被拿到,但是如果name和name2都存在,那么就根据名称去匹配,需要哪个就把名称放进传参的括号里

DI 依赖注入也可以叫做"属性装配"或者"依赖装配"

依赖可以简单认为是属性,比如下面代码中,userService 可以看做是 UserController 的属性

我们该如何完成依赖注入呢?

1.属性注入

我们用 @Autowired,这样就能把 Service 给引进来

属性注入以类型进行匹配,与注入的属性名称无关,但是如果一个类型存在多个对象时,优先进行名称匹配,如果名称都匹配不上,那就报错

@Autowired 无法注入一个被 final 修饰的属性(很少遇到这种情况)

@Controller
//用 @Controller 告诉 Spring 帮我们管理这个对象
public class UserController {
    @Autowired
    private UserService userService;
    public void doController(){
        userService.doService();
        System.out.println("do Controller...");
    }
}



@Service
public class UserService {
    public void doService(){
        System.out.println("do service....");
    }
}


@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        //Spring 上下文
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        //返回的就是 Spring 的运行环境

        UserController bean = context.getBean(UserController.class);
        bean.doController();
    }
}

运行结果如下 

2.构造方法注入

如果存只有一个构造函数,@Autowired 可以省略,当有多个构造函数的时候,默认使用无参的构造函数,如果没有无参的构造函数,我们要告诉 Spring 我们用哪个构造函数,在那个构造函数上面添加 @Autowired 就行

package com.example.ioc.controller;

import com.example.ioc.config.UserInfo;
import com.example.ioc.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
//用 @Controller 告诉 Spring 帮我们管理这个对象
public class UserController {
    //属性注入
    //@Autowired
    //private UserService userService;

    //构造方法注入
    private UserService userService;
    private UserInfo userInfo;

//    public UserController() {
//
//    }

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @Autowired
    public UserController(UserService userService, UserInfo userInfo) {
        this.userService = userService;
        this.userInfo = userInfo;
    }
    
    public void doController(){
        userService.doService();
        System.out.println("do Controller...");
    }
}

3.Setter 方法注入

public class UserController {

    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        
        this.userService = userService;
    }

    public void doController(){
        userService.doService();
        System.out.println("do Controller...");
    }
}

当程序中同一个类型有多个对象时,使用@Autowired 会报错(一些情况下)

解决方法如下:

1,属性名和你需要使用的对象名保持一致

2.使用@Primary 注解标识默认的对象,优先用它

3.使用@Qualifier 

4.使用@Resource

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

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

相关文章

2023-11-18 LeetCode每日一题(数位和相等数对的最大和)

2023-11-18每日一题 一、题目编号 2342. 数位和相等数对的最大和二、题目链接 点击跳转到题目位置 三、题目描述 给你一个下标从 0 开始的数组 nums ,数组中的元素都是 正 整数。请你选出两个下标 i 和 j(i ! j),且 nums[i] …

深入理解网络协议:通信世界的基石

💂 个人网站:【 海拥】【神级代码资源网站】【办公神器】🤟 基于Web端打造的:👉轻量化工具创作平台💅 想寻找共同学习交流的小伙伴,请点击【全栈技术交流群】 在当今数字化时代,网络协议是连接世…

Windows下安装RabbitMQ

1.安装Erlang 因为RabbitMQ是用Erlang语言编写的,所以在安装RabbitMQ之前需要先安装Erlang。 如果还未安装Erlang,官方下载安装包,点击Download Windows installer下载Erlang Downloads - Erlang/OTP 下载Erlang/OTP后,双击otp的…

JavaScript管理HTMLDOM元素(增删改查)

本文主要讲解JavaScript如何通过管理HTML上的DOM元素&#xff0c;其中包括如何查询、创建、修改以及删除具体功能和源码讲解。 增加 首先我们准备一个HTML框架和简单CSS样式&#xff0c;我对其中元素作用和关系进行一个简单说明。 <!DOCTYPE html> <html><he…

2023年道路运输企业主要负责人证考试题库及道路运输企业主要负责人试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年道路运输企业主要负责人证考试题库及道路运输企业主要负责人试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人…

C#特性(Attribute)

C#特性&#xff08;Attribute&#xff09;是一种在程序中添加元数据的机制&#xff0c;它可以为代码提供额外的信息和指示。通过使用特性&#xff0c;我们可以为类、方法、属性等元素添加标记&#xff0c;以便在运行时进行更多的操作和决策。 C#特性是一种声明式编程的工具&…

计算机网络的体系结构

目录 一. 计算机体系结构的形成二. 协议与层次划分2.1 数据传输过程2.2 什么是网络协议2.3 网络协议的三要素2.4 协议有两种形式2.4 各层协议2.5 什么是复用和分用 \quad 一. 计算机体系结构的形成 \quad 计算机网络是一个非常复杂的系统, 相互通信的两个计算机系统必须高度协调…

二叉树中的深搜之二叉树的所有路径

257. 二叉树的所有路径 - 力扣&#xff08;LeetCode&#xff09; 对于二叉树的深度搜索&#xff0c;要学会从以下三个角度来去看待问题&#xff1a; 1. 全局变量&#xff0c;有时候全局变量会减少参数的个数&#xff0c;简化很多流程&#xff1b; 这道题目&#xff0c;要返回根…

linux配置固定ip(两种方法)

首先刚下载的vm&#xff0c;刚创建的虚拟机&#xff0c;肯定是需要配置ip的 其次以前我的每次都是设置自动ip&#xff0c;这样每次登录都会自动获取ip地址&#xff0c;并且每次的ip都不相同。 ~方法&#xff1a; 开机登陆后 1)Cd /etc/sysconfig/network-scripts 2)Vi ifcf…

vue3的Watch使用详解

vue官网提到&#xff1a; watch 的第一个参数可以是不同形式的“数据源”&#xff1a;它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组&#xff1a; 1.监听单个Ref 2.监听一个getter函数 当然只修x或者y其中一个的值&#xff0c;…

LeetCode - 26. 删除有序数组中的重复项 (C语言,快慢指针,配图)

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 思路一&#xff1a;快慢指针 在数组中&#xff0c;快慢指针就是两个整数下标&#xff0c;定义 fast 和 slow 这里我们从下标1开始&#xff08;下标0的数据就1个&#xff0c;没有重复项&#xff09;&…

Java Web 实战 19 - What‘s HTTP ?

Whats HTTP ? 一 . HTTP 是什么 ?1.1 理解 HTTP 协议的工作过程1.2 HTTP 的报文格式1.2.1 准备工作1.2.2 认识 HTTP 协议的报文详情请求报文请求响应 二 . HTTP 请求报文2.1 URLURL 的 encode 2.2 HTTP 协议中的方法GETPOST常见面试题 : GET 和 POST 之间的区别 2.3 认识请求…

Java Web——JavaScript基础

1. 引入方式 JavaScript程序不能独立运行&#xff0c;它需要被嵌入HTML中&#xff0c;然后浏览器才能执行 JavaScript 代码。 通过 script 标签将 JavaScript 代码引入到 HTML 中&#xff0c;有3种方式&#xff1a; 1.1. 内嵌式(嵌入式) 直接写在html文件里&#xff0c;用s…

继承语法详解

继承语法详解 一:继承1&#xff1a;什么是继承 二&#xff1a;访问成员变量三&#xff1a;访问成员方法四&#xff1a;访问父类的成员变量和成员方法super关键字super和this关键字的区别 五&#xff1a;子类的构造方法六&#xff1a;代码块七&#xff1a;final关键字八&#xf…

Vulhub靶场-KIOPTRIX: LEVEL 1

目录 环境配置 端口扫描 漏洞发现 mod_ssl漏洞利用 Samba远程代码执行漏洞利用 环境配置 首先去官网下载靶场导入到虚拟机中 下载地址&#xff1a;Kioptrix: Level 1 (#1) ~ VulnHub 下载完成之后导入到vmware中 这里需要改nat&#xff0c;桥接模式的靶机拿不到IP&…

kubenetes-pod高可用

一、概述 实现pod层面的高可用&#xff0c;需要避免容器进程被终止避免Pod被驱逐&#xff1a; 设置合理的resources.memory limits 防止容器进程被 OOMKill&#xff0c;防止Pod被驱逐&#xff1b;设置合理的emptydir.sizeLimit 并且确保数据写入不超过emptyDir的限制&#xf…

【LeetCode刷题-双指针】--977.有序数组的平方

977.有序数组的平方 方法&#xff1a;双指针 由于数组是升序排序的&#xff0c;如果所有的数都是非负的&#xff0c;那么数组平方后&#xff0c;仍然保持升序&#xff0c;但数组中有负数&#xff0c;将每个数平方后&#xff0c;数组就会降序 需要找到数组中负数与非负数的分界…

Lec14 File systems 笔记

文件系统中核心的数据结构就是inode和file descriptor 分层的文件系统&#xff1a; 在最底层是磁盘&#xff0c;也就是一些实际保存数据的存储设备&#xff0c;正是这些设备提供了持久化存储。在这之上是buffer cache或者说block cache&#xff0c;这些cache可以避免频繁的读…

springboot321基于java的校园服务平台设计与开发

交流学习&#xff1a; 更多项目&#xff1a; 全网最全的Java成品项目列表 https://docs.qq.com/doc/DUXdsVlhIdVlsemdX 演示 项目功能演示&#xff1a; ————————————————

前端实现界面切换主题

✨ 目录 ▷ 样式切换主题▷ 变量设置主题 ▷ 样式切换主题 常用的主题切换实现方式之一&#xff0c;就是通过 link 标签的 rel 属性来实现的当 rel 标签的值是 alternate&#xff0c;就代表该样式是可以替换的title 属性要加就全加上或者全不加&#xff0c;因为 title 会导致系…