1.@Bean方法存储
类注解是添加在某个类上的,那么方法注解是添加在某个方法前的
public class UserBeans {
@Bean
public User user1(){
User user = new User();
user.setUid(001);
user.setUname("zhangsan");
user.setAge(19);
user.setPassword("123123");
return user;
}
}
当我们使用测试类去获取Bean时,发现获取不到
图一
无法正确拿到Bean的原因:
原因一:@Bean命名规则和不打雷注解的命名规则不同,@Bean存储的对象的命名默认是方法的名称
此时改动对象名称为user1(方法名),发现还是会报错
原因二:方法注解是要配合五大类注解使用
注意:无法获取到对象的原因有两个,名称必须是方法名且方法注解需要配合五大类注解
名称不能换成类名, 对象名等,加上五大类注解也不能成功获取到!!
这是spring的规定,这么做也是为了整体性能的提升,只扫描加了五大类注解的类下是否有@Bean方法注解,没有五大类注解,就不扫描该类是否有方法注解
我们看一些其他场景,一般方法名都是带动词的,get,set等等,但是对象名称是一个名词,所以直接将方法名称写进去是不太合适的.Bean名称是可以改动的,给注解设置参数即可
通过观察Bean源码发现@Bean(name = " ")和@Bean(value = " ")都可以进行设置Bean名称
还可以设置多个名称
@Bean(name = {"user","u1"})
那么设置了重命名之后,还能使用原方法名获取对象的方式还能使用吗?
答案是不能的,重命名之后默认方法名获取的方式就不能获取到Bean了
如果同一个类中有多个方法返回user呢,是否能拿到重命名后的bean?
package com.java.demo.component;
import com.java.demo.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class UserBeans {
@Bean(name = {"user","u1"})
public User user1(){
User user = new User();
user.setUid(001);
user.setUname("zhangsan");
user.setAge(19);
user.setPassword("123123");
return user;
}
@Bean
public User user2(){
User user = new User();
user.setUid(002);
user.setUname("Lisi");
user.setAge(29);
user.setPassword("321123");
return user;
}
}
是可以的,spring是允许将同一个类型的多个对象存储到容器中的
如果两个类中有相同的方法名,返回相同的user时,会出现什么情况呢?
执行多次,结果都是相同的,是因为类似于hashmap中的覆盖,zhangsan先注入,wangwu后注入,加载出来的对象就是wangwu
可使用@Order控制诸如顺序,值越小,优先级越高,越先注入,被覆盖的可能就会增大
让wangwu先注入.lisi后注入,再获取username
此时获取的是lisi这个bean
注入的方法是不能带有参数的,因为容器加载启动的时候,就会将Bean存储到容器中,而你是没有办法给传参的
2.获取Bean对象
获取Bean对象也叫做对象装配,是把对象取出来放到某个类中,也叫对象装配
实现方法有三种:
1.属性注入(Field Injection)
是日常开发使用最多的注入方式
优点是使用简单,只需要给变量添加一个注解(@Autowired)就可以在不new对象的情况下,直接获得注入的对象
注意:在静态方法中不能使用这个注解,因为静态模块是在spring加载之前就加载了的,根本获取不到
我们在controller中获取service的Bean 并使用
获取成功
缺点:
1.无法注入不可变对象
2.只适用于IoC容器,兼容性不好
3.可能违反单一设计原则
2.setter注入(Setter Injection)
优点:符合单一设计原则,每次传输的都是单个变量
缺点:
1.不能注入不可变对象
2.使用setter注入的对象可能被修改,普通的set方法支持可能被调用多次,每次可以传输不同的对象
3.构造方法注入(Spring官方推荐的注入方式)
private final UserService service;
@Autowired
public UserController(UserService service) {
this.service = service;
}
public void sayHi(){
System.out.println("com.java.demo --do userController sayHi()");
service.sayHi();
}
注意:如果当只有一个构造方法时,spring允许不加@Autowired注解!前两种方式不能进行省略,会报异常!
优点:
1.能注入不可变对象(使用final修饰的对象)
为啥属性注入,setter注入不可以呢?被final修饰的对象必须满足二者之一的条件,要么直接创建时进行赋值,要么在构造器中赋值!
2.注入的对象不会被改变,构造方法只能执行一次
3.保障注入对象完全被初始化
4.兼容性更好
还有另一个注解关键字@Resource
@Resource与@Autowired的区别
1.@Resource来自jdk,@Autowired来自Spring
2.使用时设置的参数不同,@Resource可以支持更多的参数设置
@Autowired则没有,当同一个类型的类被注入多个到spring,就需要设置一些内部属性
下文有示例,使用@Resource设置参数
3.@Resource不能用于构造方法注入
区别4:
在spring容器中找Bean,有两种方式 1.根据类型查找 2.根据名称查找
@Component
@Order(20)
public class UserBeans2 {
@Bean(name = {"user1","u1"})
public User user1(){
User user = new User();
user.setUid(001);
user.setUname("zhangsan");
user.setAge(19);
user.setPassword("123123");
return user;
}
@Bean
public User user2(){
User user = new User();
user.setUid(002);
user.setUname("wangwu");
user.setAge(29);
user.setPassword("321123");
return user;
}
}
@Component
@Order(30)
public class UserBeans {
@Bean
public User user3(){
User user = new User();
user.setUid(002);
user.setUname("Lisi");
user.setAge(29);
user.setPassword("321123");
return user;
}
}
@Autowired先根据类型查找,如果类型比较多,再根据名称查找,如果还没找到唯一的Bean,就报错
Caused by: org.springframework.beans.factory.
NoUniqueBeanDefinitionException:
No qualifying bean of type 'com.java.demo.entity.User' available:
expected single matching bean but found 2: user1,user2,user3
这里由于注入了相同类型的Bean(User),所以@Autowired还要根据名称查找,但是名称有三个,不能唯一确定,就报错了
将Controller2中的名称修改后,就能找到唯一确定的Bean
user1对应的name是zhangsan
成功找到
如果改动名字影响很大,不能改变.@Resource也解决不了,它是先根据名称查,再根据类型查找
这就是@Resource和@Autowired的第四个区别
不想改变名称,但是我们@Resource可以设置参数!!!
使用@Resource设置一个新的名称
成功拿到
@Autowired是设置不了的!
如果不使用@Reousrce.可使用@Autowired和@Qualifier同时完成获取Bean
成功获取到了
关于更加简单的存取Bean内容就结束了