注:
- 只有在扫描路径下的所有类,添加了注解才能被正确的识别并保存到 Spring 中
- 即使添加了注解,但是该类不在扫描路径下也是不能被保存到 Spring 中的
使用注解把 Bean 对象存储到 Spring 中,有两种注解类型可以选择:类注解 和 方法注解,我们下面分别来介绍:
//一共有五种类注解可以进行对象的注册:
@Controller
public class ArticleController {
public String sayHello(){
return "hello,controller";
}
}
@Service
public class UserService {
public String sayHello(){
return "hello,service";
}
}
@Repository
public class UserRepository {
public String sayHello(){
return "hello,repository";
}
}
@Configuration
public class UserConfiguration {
public String sayHello(){
return "hello,configuration";
}
}
@org.springframework.stereotype.Component
public class Component {
public String sayHello(){
return "hello,component";
}
}
//先使用上下文的方式来获取对象,下面介绍更简单的获取对象的方式:
//当使用5大类注解获取bean时,默认 只需要将类名首字母小写即可, 如果bean对象的首字母和第二个字母都是大写时,需要使用原类名才能正确获取到bean对象
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
ArticleController articleController = context.getBean("articleController",ArticleController.class);
System.out.println(articleController.sayHello());
UserService userService = context.getBean("userService",UserService.class);
System.out.println(userService.sayHello());
UserRepository userRepository = context.getBean("userRepository",UserRepository.class);
System.out.println(userRepository.sayHello());
Component component = context.getBean("component",Component.class);
System.out.println(component.sayHello());
UserConfiguration userConfiguration = context.getBean("userConfiguration",UserConfiguration.class);
System.out.println(userConfiguration.sayHello());
在这里使用五个类注解,是为了让程序员看到类注解之后就能直接了解到当前类的用途,不同的类注解的用途是不同的:
注:@Component注解是其他四个注解的父类
我们配置扫描路径来注册 Bean 对象时并没有设置对象的 id ,那我们通过上下文的方式来获取对象时该使用什么 id 呢?
//我们查看Spring的源码来获取答案:
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
// 如果第⼀个字⺟和第⼆个字⺟都为⼤写的情况,是把 bean 的⾸字⺟也⼤写存储了
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
// 否则就将⾸字⺟⼩写
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
注:通过源码我们可以知道:
- 我们通过上下文获取对象的时候,直接使用类名作为 id 即可
- 默认情况下,直接将类名的首字母小写作为 id 使用即可;如果类名的首字母和第二个字母都是大写时,需要使用原类名作为 id 使用。
@Component
public class StudentBeans {
@Bean
public Student student(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(18);
return student;
}
}
注:
- 类注解是添加到某个类上的;方法注解是添加到某个方法上的。
- 方法注解要搭配五大类注解一起使用
- 方法注解是为了解决不能多次注册同一个类的问题
@Component
public class StudentBeans {
@Bean(name = {"s1","s2"})
public Student student(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(18);
return student;
}
}
注:
- 重命名Bean后,使用Spring上下文来获取对象时,必须把重命名后的名字作为 id 来使用
- 方法注解重命名Bean后解决了不能多次注册同一个类的问题
我们通过 Spring 注入的方式来更加简单的获取 Bean 对象,一共有三种注入方式:
@Autowired
private StudentService studentService;
优点:使用简单
缺点:
- 不能注入不可变对象(final对象),因为final类型的变量在调用class的构造函数的这个过程当中就得初始化完成,基于字段的注入是使用set形式注入的
- 只适用于Ioc容器
- 更容易违背单一设计原则:针对类级
private StudentService studentService;
@Autowired
public void setStudentService(StudentService studentService){
this.studentService = studentService;
}
优点:更符合单一设计原则:针对方法级别
缺点:
- 不能注入不可变对象(final对象),因为final类型的变量在调用class的构造函数的这个过程当中就得初始化完成,基于字段的注入是使用set形式注入的
- 注入对象可被修改
private StudentService studentService;
//当类中只有一个构造方法时 @Autowired可以省略
//如果类中有多个构造方法(重载)时,需要加上@Autowired来明确使用哪个构造方法来注入对象
@Autowired
public StudentController(StudentService studentService){
this.studentService = studentService;
}
优点:
- 可以注入一个不可变对象(final对象)
- 注入的对象可以被修改(可以被final修饰、构造方法只执行一次)
- 注入的对象会被完全初始化
- 通用性更好
缺点:没有属性注入简单
注入多个相同类型的 Bean 对象,有两种解决方案:
@Resource(name="student1")
private Student student1;
@Resource(name="student2")
private Student student2;
@Autowired
@Qualifier(value="student1")
private Student student1;
@Autowired
@Qualifier(value="student2")
private Student student2;
相同点:都是用来实现依赖注入的
不同点: