当前位置: 首页 > news >正文

Spring中Bean的相关注解

目录

1.Spring IoC&DI

2.关于Bean存储的相关注解(类注解与方法注解)

Bean的获取方式

类注解和方法注解的重命名

2.1 类注解

2.1.1 @Controller

2.1.2 @Service

2.1.3 @Repository

2.1.4 @Component

2.1.5 @Configuration

2.2 方法注解-@Bean

2.2.1 定义多个对象

2.2.2 扫描路径-@ComponentScan

3.DI注入方式-@Autowired

3.1 属性注入

3.2 Setter方法注入

3.3 构造方法注入

3.4 三种注入方式的优缺点

3.5 @Autowired存在的问题及解决方法


1.Spring IoC&DI

Spring是包含了众多工具方法的一个IoC容器

  • IoC(Inversion of Control,控制反转),是Spring的一个核心思想,简单来说就是将对象之间层层的依赖关系反转过来(一开始是使用方创建并控制依赖对象,现在是把依赖对象注入到当前对象中),使得依赖对象无论发生什么改变,当前类都不受影响,大大降低了代码的耦合度
  • IoC容器就是创建并管理这些对象的容器,不再需要用户自己去创建对象,而是交给IoC容器去创建并对对象进行统一管理(将对象的控制权交给Spring)
  • DI(Dependency  Injection,依赖注入),是IoC的一种具体实现,依赖注入是一个过程,在Ioc容器在创建Bean时,去提供运行时所依赖的资源,这个资源就是对象,简单点说,依赖注入就是把对象取出来放到某个类的属性中

2.关于Bean存储的相关注解(类注解与方法注解)

Bean:Spring是一个IoC容器,而IoC容器中装的就是Bean(对象)

Bean的获取方式

Bean的获取方式有很多,常用的是以下三种

Object getBean(String name) throws BeansException根据Bean名称获取Bean
<T> T getBean(String name, Class<T> requiredType) throws BeansException根据Bean名称和类型获取Bean
<T> T getBean(Class<T> requiredType) throws BeansException根据类型获取Bean

Bean名称:当使用的是类注解时,Bean的名称为类名的小驼峰(第一个单词以小写字母开始,后面每个单词首字母大写),如果类名前两个字母都是大写,则Bean名称为类名;当使用的是方法注解时,Bean名称就是方法名

注:对同一个类获取多次Bean,指向的是同一个对象(类似单例模式,有且仅有一个对象)

类注解和方法注解的重命名

类注解重命名:类注解+(新名称)

//启动类代码
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Demo3Application {public static void main(String[] args) {ApplicationContext context=SpringApplication.run(Demo3Application.class, args);UserComponent userComponent=(UserComponent) context.getBean("user1");//获取名称为user1的Bean//如果再去获取原来名称为userComponent的Bean,会报错userComponent.sayHi();}
}//UserComponent类
package com.example.demo;
import org.springframework.stereotype.Component;
@Component("user1")//重命名为user1
public class UserComponent {public void sayHi(){System.out.println("Hi, I'm UserComponent");}
}

方法注解重命名:@Bean+(新名称)

//启动类代码
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Demo3Application {public static void main(String[] args) {ApplicationContext context=SpringApplication.run(Demo3Application.class, args);UserInfo userInfo1=(UserInfo) context.getBean("user1");UserInfo userInfo2=(UserInfo) context.getBean("user2");System.out.println(userInfo1);System.out.println(userInfo2);}
}//BeanTest类
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class BeanTest {@Bean("user1")//重命名为user1public UserInfo userInfo1(){return new UserInfo("zhangsan",1);}@Bean("user2")//重命名为user2public UserInfo userInfo2(){return new UserInfo("lisi",2);}
}

注:类注解和方法注解的重命名的名称可以有多个, 使用{ }来标识,例如@Component({"user1","user2"})

2.1 类注解

类注解总共有五种,这些注解都有各自不同的应用场景

  • @Controller:控制层(Controller),接收请求,对请求进行处理并进行响应
  • @Service:业务逻辑层(Service),处理具体的业务逻辑
  • @Repository:数据访问层(Dao),负责数据访问操作
  • @Configuration:配置层,处理项目中的一些配置信息
  • @Component:元注解,上述四种注解都含有@Component

2.1.1 @Controller

//启动类代码(从Spring中获取Bean)
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Demo3Application {public static void main(String[] args) {ApplicationContext context=SpringApplication.run(Demo3Application.class, args);UserController userController=(UserController) context.getBean("userController");userController.sayHi();}
}//UserController类
package com.example.demo;
import org.springframework.stereotype.Controller;
@Controller//将对象存储到Spring中
public class UserController {public void sayHi(){System.out.println("Hi,I'm UserController");}
}

2.1.2 @Service

//启动类代码(从Spring中获取Bean)
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Demo3Application {public static void main(String[] args) {ApplicationContext context=SpringApplication.run(Demo3Application.class, args);UserService userService=(UserService) context.getBean("userService");userService.sayHi();}
}//UserService类
package com.example.demo;
import org.springframework.stereotype.Service;
@Service//将对象存储到Spring中
public class UserService {public void sayHi(){System.out.println("Hi, I'm UserService");}
}

2.1.3 @Repository

//启动类代码(从Spring中获取Bean)
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Demo3Application {public static void main(String[] args) {ApplicationContext context=SpringApplication.run(Demo3Application.class, args);UserRepository userRepository=(UserRepository) context.getBean("userRepository");userRepository.sayHi();}
}//UserRepository类
package com.example.demo;
import org.springframework.stereotype.Repository;
@Repository//将对象存储到Spring中
public class UserRepository {public void sayHi(){System.out.println("Hi,I'm UserRepository");}
}

2.1.4 @Component

//启动类代码(从Spring中获取Bean)
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Demo3Application {public static void main(String[] args) {ApplicationContext context=SpringApplication.run(Demo3Application.class, args);UserComponent userComponent=(UserComponent) context.getBean("userComponent");userComponent.sayHi();}
}//UserComponent类
package com.example.demo;
import org.springframework.stereotype.Component;
@Component//将对象存储到Spring中
public class UserComponent {public void sayHi(){System.out.println("Hi, I'm UserComponent");}
}

2.1.5 @Configuration

//启动类代码(从Spring中获取Bean)
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Demo3Application {public static void main(String[] args) {ApplicationContext context=SpringApplication.run(Demo3Application.class, args);UserConfiguration userConfiguration=(UserConfiguration) context.getBean("userConfiguration");userConfiguration.sayHi();}
}//UserConfiguration类
package com.example.demo;
import org.springframework.context.annotation.Configuration;
@Configuration//将对象存储到Spring中
public class UserConfiguration {public void sayHi(){System.out.println("Hi,I'm UserConfiguration");}
}

2.2 方法注解-@Bean

当一个类需要多个对象,或者需要使用外部包里的类时,使用类注解无法满足需求,这时就需要用到方法注解@Bean

2.2.1 定义多个对象

//启动类代码(从Spring中获取Bean)
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Demo3Application {public static void main(String[] args) {ApplicationContext context=SpringApplication.run(Demo3Application.class, args);//如果这里使用类名获取Bean,会由于得到多个Bean而报错,所以需要使用上述Bean获取方式中的第1或第2种UserInfo userInfo1=(UserInfo) context.getBean("userInfo1");//获取方法名为userInfo1对应的BeanUserInfo userInfo2=(UserInfo) context.getBean("userInfo2");//获取方法名为userInfo2对应的BeanSystem.out.println(userInfo1);System.out.println(userInfo2);}
}//BeanTest类
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component//方法注解需要搭配类注解一起使用,否则会报错
public class BeanTest {@Beanpublic UserInfo userInfo1(){return new UserInfo("zhangsan",1);}@Beanpublic UserInfo userInfo2(){return new UserInfo("lisi",2);}
}

2.2.2 扫描路径-@ComponentScan

Spring的扫描路径默认为启动类(@SpringBootApplication注释的类)所在的路径,如果路径下有被类注解注释的类,就会将该类的对象存储到Spring中。如果想要修改默认路径,可以通过@ComponentScan来指定扫描路径

//添加到启动类中,路径要和默认路径不同
@ComponentScan("com.example.demo.test")
//指定单个扫描路径
@ComponentScan({"com.example.demo.test","com.example.demo.test1"})
//指定多个扫描路径

3.DI注入方式-@Autowired

@Autowired注释的作用主要是从Spring中获取对象,注入到对象的使用方(根据类型注入)。对于DI注入,Spring提供了三种方式,分别是属性注入,Setter方法注入以及构造方法注入

3.1 属性注入

属性注入使用@Autowire实现,以下是使用属性注入实现Service类注入到Controller类的一个简单例子

//启动类代码(获取UserController对象中,调用sayHi方法)
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Demo3Application {public static void main(String[] args) {ApplicationContext context=SpringApplication.run(Demo3Application.class, args);UserController userController=(UserController) context.getBean("userController");userController.sayHi();}
}//UserController类
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {//使用属性注入将Service类注入到Controller类中@Autowiredprivate UserService userService;public void sayHi(){System.out.println("Hi,I'm UserController");userService.sayHi();}
}//UserService类
package com.example.demo;
import org.springframework.stereotype.Service;
@Service
public class UserService {public void sayHi(){System.out.println("Hi, I'm UserService");}
}

3.2 Setter方法注入

Setter方法注入即在设置set方法时加上@Autowired注解

//UserController类
//启动类代码和UserService类与属性注入中一致
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {private UserService userService;//使用Setter方法注入将Service类注入到Controller类中@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("Hi,I'm UserController");userService.sayHi();}
}

3.3 构造方法注入

构造方法注入即在类的构造方法中实现注入

注:使用构造方法注入时,如果注入的类只有一个构造方法,那么@Autowired可以省略,如果注入的类有多个构造方法,那么需要添加@Autowired来明确指定使用哪个构造方法,否则会报错

//UserController类
//启动类代码和UserService类与属性注入中一致
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {private UserService userService;//使用构造方法注入将Service类注入到Controller类中@Autowiredpublic UserController(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("Hi,I'm UserController");userService.sayHi();}
}

3.4 三种注入方式的优缺点

属性注入

  • 优点:简介,方便使用
  • 缺点:只能用于Ioc容器;不能注入一个Final修饰的属性

Setter方法注入

  • 优点:方便在类实例之后,重新对该对象进行配置或者注入
  • 缺点:不能注入一个Final修饰的属性;注入对象可能会被改变

构造方法注入

  • 优点:可以注入Final修饰的属性;注入的对象不会被修改;依赖对象被使用前一定会被完全初始化;通用性好,更换任何框架都可适用
  • 缺点:注入多个对象时,代码比较繁琐

3.5 @Autowired存在的问题及解决方法

当同一个类型存在多个Bean时,使用@Autowired会存在问题

//启动类代码
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Demo3Application {public static void main(String[] args) {ApplicationContext context=SpringApplication.run(Demo3Application.class, args);UserController userController=context.getBean(UserController.class);userController.sayHi();}
}//UserController类
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {@Autowired//注入UserInfoprivate UserInfo userInfo;public void sayHi(){System.out.println("Hi,I'm UserController");System.out.println(userInfo);}
}//BeanTest类
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class BeanTest {@Beanpublic UserInfo userInfo1(){return new UserInfo("zhangsan",1);}@Beanpublic UserInfo userInfo2(){return new UserInfo("lisi",2);}
}

@Autowired注解会根据类型UserInfo去查找Bean,找到userInfo1和userInfo2两个方法,由于查找到的Bean只能是唯一的,所以程序会报错(非唯一的Bean)。那么如何解决这个问题呢?Spring提供了几个解决方法:@Primary,@Qualifier,@Resource

@Primary:当同个类型存在多个Bean注入时,添加@Primary注解用来确定默认的实现

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@Component
public class BeanTest {@Primary//指定该Bean为Bean的默认实现@Beanpublic UserInfo userInfo1(){return new UserInfo("zhangsan",1);}@Beanpublic UserInfo userInfo2(){return new UserInfo("lisi",2);}
}

@Qualifier:添加@Qualifier(Bean的名称),指定当前要注入的Bean(@Qualifier需要搭配@Autowired使用,不能单独使用)

package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {@Qualifier("userInfo1")//指定Bean名称为userInfo1@Autowiredprivate UserInfo userInfo;public void sayHi(){System.out.println("Hi,I'm UserController");System.out.println(userInfo);}
}

@Resource:与@Qualifier用法相同,也是指定Bean的名称进行注入,但不需要搭配@Autowired

package com.example.demo;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {@Resource(name="userInfo1")//指定Bean名称为userInfo1并注入private UserInfo userInfo;public void sayHi(){System.out.println("Hi,I'm UserController");System.out.println(userInfo);}
}

除了上述三种使用注解的解决方法,还可以通过改变对象名称,使其与要注入的Bean的名称相同

package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {@Autowiredprivate UserInfo userInfo1;//注入Bean名称为userInfo1,则对象名称也为userInfo1public void sayHi(){System.out.println("Hi,I'm UserController");System.out.println(userInfo1);}
}
http://www.lryc.cn/news/433182.html

相关文章:

  • Golang | Leetcode Golang题解之第385题迷你语法分析器
  • 【Java 优选算法】双指针(上)
  • 【自动驾驶】控制算法(八)横向控制Ⅰ | 算法与流程
  • Android SSE 单向接收数据
  • 排序《数据结构》
  • flutter 提示框2 Dialog
  • 如何选择SDR无线图传方案
  • 关于Python类中方法__init__()解析
  • 微信小程序 自定义组件
  • Mac+Pycharm配置PyQt6教程
  • 如何保证Redis与Mysql双写一致性?
  • 9.8笔试记录
  • SRE-系统管理篇
  • 傅里叶级数,傅里叶变换
  • 零知识证明在BSV网络上的应用
  • 无任何门槛!3分钟5步,发布属于你的第一个智能体小程序,99%的人还不知道怎么用
  • 怎么强制撤销excel工作表保护?
  • 每天学习一个字符串类函数之memmove函数
  • 【机器人工具箱Robotics Toolbox开发笔记(十三)】三自由度机器人圆弧轨迹规划仿真实例
  • 软件工程-图书管理系统的概要设计
  • springboot 整合swagger
  • Flutter 进阶:绘制加载动画
  • 【深度学习】梯度下降法
  • 基于机器学习的电商优惠券核销预测
  • PHP-FPM 远程代码执行漏洞(CVE-2019-11043)复现
  • Rust : 从事量化的生态现状与前景
  • Java项目——苍穹外卖(一)
  • 20240908 每日AI必读资讯
  • HNU-2023电路与电子学-实验3
  • html基础语法 看这一篇就够了!