Bean相关的知识

在这里插入图片描述

在IOC和DI的场景中,bean这个概念十分重要
下面我简单做一个总结

IOC(控制反转)

要想把某个对象交给IOC容器来管理,需要通过注解来实现
注解分为两类:

  1. 类注解: @Controller、@Service、@Repository、@Component、@Configuration
  2. 方法注解: @Bean(需要搭配类注解使用,否则会失效报错)

接下来就是考虑如何从容器中获取对象

通过类对象获取对象

@Controller // 将对象存储到 Spring 中
public class UserController {
	public void sayHi(){
		System.out.println("hi,UserController...");
	}
}
@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
		//获取Spring上下⽂对象
		ApplicationContext context = SpringApplication.run(SpringIocDemoApplication .class, args);
		//从Spring上下⽂中获取对象
		UserController userController = context.getBean(UserController.class);
		//使⽤对象
		userController.sayHi();
	}
}

这个场景是通过类名来获取对象,但是如果一个类有多个bean对象呢
我们查看源码可以发现,ApplicationContext获取bean对象的功能是继承了父类BeanFactory的功能,而BeanFactory还有其他获取bean对象的方法,也就解决了上述问题

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";

    // 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;

    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);

    boolean containsBean(String var1);

    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;

    String[] getAliases(String var1);
}

源码中1,2涉及到bean的名称,那么什么是bean的名称呢

bean的命名规范

官方文档

在这里插入图片描述
bean名称以小写字母开头,然后使用驼峰式大小写.
比如
类名:UserController,Bean的名称为:userController
类名:AccountManager,Bean的名称为:accountManager
类名:AccountService,Bean的名称为:accountService

也有⼀些特殊情况,当有多个字符并且第一个和第二个字符都是大写时,将保留原始的大小写.这些规则与java.beans.Introspector.decapitalize(Spring在这里使用)定义的规则相同
比如
类名:UController,Bean的名称为:UController
类名:AManager,Bean的名称为:AManager

一个类多个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;
	}
}
@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

对于五大注解来说
通过 value属性设置 @Controller(value = “user”)
对于@bean来说是②通过name属性设置 @Bean(name = {“u1”,“user1”})

@Bean(name = {"u1","user1"})
public User user1(){
	User user = new User();
	user.setName("zhangsan");
	user.setAge(18);
	return user;
}

DI(依赖注入)

注入方式

对于依赖注入,spring也有三种方式

  1. 属性注入
@Autowired
private UserService userService;
  1. 构造方法注入
@Controller
public class UserController2 {
	//注⼊⽅法2: 构造⽅法
	private UserService userService;
	@Autowired
	public UserController2(UserService userService) {
		this.userService = userService;
	}
	public void sayHi(){
		System.out.println("hi,UserController2...");
		userService.sayHi();
	}
}

如果类只有⼀个构造方法,那么@Autowired注解可以省略;如果类中有多个构造方法,那么需要添加上@Autowired来明确指定到底使用哪个构造方法
3. setter注入

@Controller
public class UserController3 {
//注⼊⽅法3: Setter⽅法注⼊
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
	this.userService = userService;
}
public void sayHi(){
	System.out.println("hi,UserController3...");
	userService.sayHi();
	}
}


上述代码在一个类中只有一个bean对象的时候,使用@Autowired/没有问题
但是如果存在多个bean对象的时候,就会报错,因为编译器也不知道具体该注入哪一个bean对象
因此,spring提供了以下几种解决办法

注入注解

1.@Primary确定默认的注入对象

@Component
public class BeanConfig {
@Primary //指定该bean为默认bean的实现
@Bean("u1")
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;
	}
}

2.@Qualifier 指定当前要注入的bean对象。在@Qualifier的value属性中,指定注入的bean的名称。@Qualifier注解不能单独使用,必须配合@Autowired使用

@Controller
public class UserController {
@Qualifier("user2") //指定bean名称
@Autowired
private User user;
public void sayHi(){
	System.out.println("hi,UserController...");
	System.out.println(user);
	}
}

3.@Resource 是按照bean的名称进行注入。通过name属性指定要注入的bean的名称

@Controller
public class UserController {
@Resource(name = "user2")
private User user;
public void sayHi(){
	System.out.println("hi,UserController...");
	System.out.println(user);
	}
}

@Autowird与@Resource的区别
• @Autowired是spring框架提供的注解,而@Resource是JDK提供的注解
• @Autowired默认是按照类型注入而@Resource是按照名称注入

bean的作用域

在Spring中支持6中作用域,后4种在Spring MVC环境才生效

  1. singleton:单例作用域 每个Spring IoC容器内同名称的bean只有⼀个实例(单例)(默认)
  2. prototype:原型作用域(多例作用域)每次使用该bean时会创建新的实例(非单例)
  3. request:请求作用域 每个HTTP 请求生命周期内, 创建新的实例(web环境中)
  4. session:会话作用域 每个HTTP Session生命周期内, 创建新的实例(web环境中)
  5. Application: 全局作用域 每个ServletContext生命周期内, 创建新的实例(web环境中)
  6. websocket:HTTP WebSocket 作用域 每个WebSocket生命周期内, 创建新的实例(web环境中)
@Component
public class DogBeanConfig {
 @Bean
 public Dog dog(){
	 Dog dog = new Dog();
	 dog.setName("旺旺");
	 return dog;
 }
 @Bean
 @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
 public Dog singleDog(){
	 Dog dog = new Dog();
	 return dog;
 }
 @Bean
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public Dog prototypeDog(){
	 Dog dog = new Dog();
	 return dog;
 }
 @Bean
 @RequestScope
 public Dog requestDog() {
	 Dog dog = new Dog();
	 return dog;
 }
 
 @Bean
 @SessionScope
 public Dog sessionDog() {
	 Dog dog = new Dog();
	 return dog;
 }
 
 @Bean
 @ApplicationScope
 public Dog applicationDog() {
	 Dog dog = new Dog();
	 return dog;
 }
}

bean的生命周期

生命周期指的是⼀个对象从诞生到销毁的整个生命过程, 我们把这个过程就叫做⼀个对象的生命周期.
Bean 的生命周期分为以下5个部分:

  1. 实例化(为Bean分配内存空间)
  2. 属性赋值(Bean注入和装配, 比如@AutoWired )
  3. 初始化
    a. 执行各种通知, 如 BeanNameAware , BeanFactoryAware ,
    ApplicationContextAware 的接口方法.
    b. 执行初始化方法
    ▪ xml定义 init-method
    ▪ 使用注解的方式@PostConstruct
    ▪ 执行初始化后置方法( BeanPostProcessor )
  4. 使用Bean
  5. 销毁Bean
    a. 销毁容器的各种方法, 如 @PreDestroy , DisposableBean 接口方法, destroy method
    实例化和属性赋值对应构造方法和setter方法的注入. 初始化和销毁是用户能自定义扩展的两个阶段,可以在实例化之后, 类加载完成之前进行自定义"事件"处理
  • 19
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值