Spring IocDI(二)
前言:
上篇博客简单了解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 {@Beanpublic 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 {@Beanpublic User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}@Beanpublic 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启动类所在的包以及子包。