前言:
上篇博客简单了解Ioc&DI的概念以及使用,这篇博客内容是Ioc详解和多种注解的具体使用
Ioc详解
前文我们所了解到的Ioc控制反转,就是将对象交给Spring的Ioc容器,由Ioc容器创建和管理对象,这一过程也成为Bean的存储
什么是Bean?
交由Spring容器进行存储管理的对象,统称为Bean。
Bean的特点:
①Bean的创建、销毁、依赖注入都由Spring控制,而不是开发者手动处理
②Bean的定义——无论是XML、@Component注解还是Java配置类注解@Configuration,都可以声明Bean的变量
③Bean一般情况下默认是单例模式
要将对象交给Spring进行管理,需要在其类上面添加注解,能够实现这个目的的注解分为两类——类注解以及方法注解
类注解:@Component @Controller @Configuration @Service @Repository
方法注解:@Bean
@Component是通用的Bean存储注解,由于开发会对整个项目进行代码分成,@Component衍生出对应的层所使用的注解,例如控制层衍生出@Controller(Web层),类似的注解还有@Service(业务逻辑层)以及@Repository(数据访问层DAO)
@Controller(控制器存储)
使用@Controller注解的方式进行Bean的存储
@Controller // 将对象存储到 Spring 中
public class UserController {
public void sayHi(){
System.out.println("hi,UserController...");
}
}
既然会存储Bean了,由该怎么获取Bean呢?——使用ApplicationContext进行获取
@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();
}
}
把注解去掉,Spring扫描不到Bean就会报错
@Service(服务存储)
类似上述@Controller的存储方式进行存储
@Service
public class UserService {
public void sayHi(String name) {
System.out.println("Hi," + name);
}
}
依旧使用ApplicationContext获取类,由类调用方法去获取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();
}
}
去掉注解依旧会扫描不到Bean,其实@Service功能上和@Component没差别,就是为了代码客观性满足应用分层的设计理念
方法注解@Bean
不同于上述的类注解,方法注解则是添加在类的构造方法上,而且方法注解往往需要搭配类注解进行使用
@Component
public class BeanConfig {
@Bean
public User user(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
}
获取Bean
@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);
}
}
现在有一个很明显的问题,一个类可以有多个构造方法,那我能不能有多个Bean?
答案是可以的,但是Bean一般是单例模式,定义多个Bean在扫描获取Bean的时候就需要通过具体的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;
}
}
通过ApplicationContext获取Bean,报错信息表示在扫描的时候预期只会匹配一个Bean,但是目前有两个
这是直接用getBean获取Bean会产生的错误,通过具体的Bean名称去获取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名”}),单个Bean名可以直接@Bean("Bean名")
public class User{
@Bean(name = {"u1","user1"})
public User user1(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
}
可以直接通过使用u1来获取对象
@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的扫描路径下。Spring的扫描路径默认是SpringBoot启动类所在的包以及子包。