目录
一、IoC介绍
IoC: Inversion of Control (控制反转),也就是说 Spring 是一个"控制反转"的容器。就是将对象的 控制权交给Spring的IOC容器,由IOC容器创建及管理对象,也就是bean的存储。二、Bean存储
Spring存储对象的注解有:
- 类注解:@Controller、@Service、@Repository、@Component、@Configuration
- 方法注解:@Bean
2.1 @Controller(控制器存储)
使用@Controller 存储 bean 的代码如下所示:@Controller // 将对象存储到 Spring 中
public class UserController {
public void sayHi(){
System.out.println("hi,UserController...");
}
}
从Spring容器中获取对象:
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下⽂对象
ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
//从Spring上下⽂中获取对象
UserController bean = context.getBean(UserController.class);
//使⽤对象
bean.sayHi();
}
ApplicationContext,也就是Spring上下文,Spring的运行环境。
运行结果如下:
2.1.1 获取bean对象的其他方式
ApplicationContext 也提供了其他获取bean的方式, ApplicationContext 获取bean对象的功能, 是父类BeanFactory提供的功能。public interface BeanFactory {
//以上省略...
// 1. 根据bean名称获取bean
Object getBean(String var1) throws BeansException;
// 2. 根据bean名称和类型获取bean
<T> T getBean(String var1, Class<T> var2) throws BeansException;
// 3. 按bean名称和构造函数参数动态创建bean,只适⽤于具有原型(prototype)作⽤域的bean
Object getBean(String var1, Object... var2) throws BeansException;
// 4. 根据类型获取bean
<T> T getBean(Class<T> var1) throws BeansException;
// 5. 按bean类型和构造函数参数动态创建bean, 只适⽤于具有原型(prototype)作⽤域的bean
<T> T getBean(Class<T> var1, Object... var2) throws BeansException;
//以下省略...
}
常用的是上述1,2,4种, 这三种方式,获取到的bean是⼀样的。其中1,2种都涉及到根据名称来获取对象。那么bean的名称是什么呢?
2.1.2 Bean的命名约定
命名约定使用Java标准约定作为实例字段名。 也就是说,bean名称以小写字母开头,然后使用驼峰式大小写。比如:类名: UserController, Bean的名称为: userController 类名: AccountManager, Bean的名称为: accountManager 类名: AccountService, Bean的名称为: accountService也有一些特殊情况,当有多个字符并且第一个和第二个字符都是大写时,将保留原始的大写。 这些规则与java.beans.Introspector.decapitalize (Spring在这里使用的)定义的规则相同。比如:
类名: UController, Bean的名称为: UController 类名: AManager, Bean的名称为: AManager
根据这个命名规则,以下方法可以获取Bean:
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下⽂对象
ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
//从Spring上下⽂中获取对象
//根据bean类型, 从Spring上下⽂中获取对象
UserController userController1 = context.getBean(UserController.class);
//根据bean名称, 从Spring上下⽂中获取对象
UserController userController2 = (UserController)context.getBean("userController");
//根据bean类型+名称, 从Spring上下⽂中获取对象
UserController userController3 = context.getBean("userController",UserController.class);
System.out.println(userController1);
System.out.println(userController2);
System.out.println(userController3);
}
}
获取bean对象, 是父类BeanFactory提供的功能。常见面试题:
ApplicationContext VS BeanFactory
- 继承关系和功能方面来说:Spring 容器有两个顶级的接口:BeanFactory 和 ApplicationContext。其中 BeanFactory 提供了基础的访问容器的能力,而 ApplicationContext 属于 BeanFactory 的子类,它除了继承了 BeanFactory 的所有功能之外, 它还拥有独特的特性,还添加了对国际化支持、资源访问支持、以及事件传播等方面的支持。
- 从性能方面来说:ApplicationContext 是一次性加载并初始化所有的 Bean 对象,而BeanFactory 是需要哪个才去加载哪个,因此更加轻量。(空间换时间)
2.2 @Service(服务存储)
使用@Service 存储 bean 的代码如下所示:
@Service
public class UserService {
public void sayHi(String name) {
System.out.println("hi,UserService...");
}
}
读取 bean 的代码:
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下⽂对象
ApplicationContext context =
SpringApplication.run(SpringIocDemoApplication.class, args);
//从Spring中获取UserService对象
UserService userService = context.getBean(UserService.class);
//使⽤对象
userService.sayHi();
}
}
运行结果如下:
2.3 @Repository(仓库存储)
使用@Repository存储bean的代码如下:
@Repository
public class UserRepository {
public void sayHi() {
System.out.println("Hi,UserRepository...");
}
}
读取bean的代码:
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下⽂对象
ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
//从Spring上下⽂中获取对象
UserRepository userRepository = context.getBean(UserRepository.class);
//使⽤对象
userRepository.sayHi();
}
}
运行结果如下:
2.4 @Component(组件存储)
使用@Component存储bean的代码如下:
@Component
public class UserComponent {
public void sayHi() {
System.out.println("Hi,UserComponent...");
}
}
读取bean的代码:
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下⽂对象
ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
//从Spring上下⽂中获取对象
UserComponent userComponent = context.getBean(UserComponent.class);
//使⽤对象
userComponent.sayHi();
}
}
运行结果如下:
2.5 @Configuration(配置存储)
使用 @Configuration 存储 bean 的代码如下所示:@Configuration
public class UserConfiguration {
public void sayHi() {
System.out.println("Hi,UserConfig...");
}
}
读取bean的代码:
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下⽂对象
ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
//从Spring上下⽂中获取对象
UserConfiguration userConfiguration = context.getBean(UserConfiguration.class);
//使⽤对象
userConfiguration.sayHi();
}
}
运行结果如下:
NOTE: 为什么要这么多类注解?
查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:其实这些注解里面都有一个注解 @Component ,说明它们本身就是属于 @Component 的"子类"。 @Component 是一个元注解,也就是说可以注解其他类注解,如 @Controller , @Service , @Repository 等。 这些注解被称为 @Component 的衍生注解。 @Controller , @Service 和 @Repository 用于 更具体的用例(分别在控制层, 业务逻辑层, 持 久化层), 在开发过程中, 如果你要在业务逻辑层使用 @Component 或@Service,显然@Service是更好的选择。
2.6 方法注解@Bean
类注解是添加到某个类上的,但是存在两个问题:- 使用外部包里的类,没办法添加类注解;
- ⼀个类,需要多个对象,比如多个数据源;
2.6.1 方法注解的使用
在 Spring 框架的设计中,方法注解 @Bean 要配合类注解才能将对象正常的存储到 Spring 容器中, 如下代码所示:@Component
public class BeanConfig {
@Bean
public User user(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
}
获取bean对象中的user:
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下⽂对象
ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
//从Spring上下⽂中获取对象
User user = context.getBean(User.class);
//使⽤对象
System.out.println(user);
}
}
运行结果如下:
2.6.2 定义多个对象
@Bean的使用:@Component
public class BeanConfig {
@Bean
public User user1(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
@Bean
public User user2(){
User user = new User();
user.setName("lisi");
user.setAge(19);
return user;
}
}
根据名称来获取bean对象:
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下⽂对象
ApplicationContext context =
SpringApplication.run(SpringIocDemoApplication.class, args);
//根据bean名称, 从Spring上下⽂中获取对象
User user1 = (User) context.getBean("user1");
User user2 = (User) context.getBean("user2");
System.out.println(user1);
System.out.println(user2);
}
}
运行结果如下:
@Bean注解的bean,bean的名称就是它的方法名。2.6.3 重命名Bean
可以通过设置 name 属性给 Bean 对象进行重命名操作,如下代码所示:@Bean(name = {"u1","user1"})
public User user1(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
此时我们使用 u1 就可以获取到 User 对象了,如下所示:
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下⽂对象
ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
//从Spring上下⽂中获取对象
User u1 = (User) context.getBean("u1");
//使⽤对象
System.out.println(u1);
}
}
2.7 扫描路径
使用五大注解声明的bean,要想生效,还需要配置扫描路径,让Spring扫描到这些注解。也就是通过在启动类中添加 @ComponentScan 来配置扫描路径。默认扫描的范围是SpringBoot启动类所在包及其子包。@ComponentScan({"com.example.demo"})
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下⽂对象
ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
//从Spring上下⽂中获取对象
User u1 = (User) context.getBean("u1");
//使⽤对象
System.out.println(u1);
}
}
但是此做法不做推荐,那么推荐做法为:
把启动类放在希望扫描的包的路径下, 这样定义的bean就都可以被扫描到。 标签:一文,对象,Spring,Bean,public,bean,IoC,class From: https://blog.csdn.net/m0_60462557/article/details/140608198