Spring容器创建对象的两种方式
一、自己创建的类(可以添加注解)
1、创建实体类Student(添加注解@Component)
@Component
//@Scope("prototype")
//singleton:单例作用域,SPring容器中该类型的对象只有一个,无论获取多少次
//优点:节省内存,缺点:不能做到个性化属性的赋值或修改
//prototype:原型作用域:Spring容器中该类型的对象每获取一次,就会创建一个 新的对象返回
//优点:能做到个性化属性的赋值或修改,缺点:占用内存过多
public class Student {
private Integer id;
private String username;
private String gender;
@Override
public String toString() {
return "Student{" +
"id=" + id +
", username='" + username + '\'' +
", gender='" + gender + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
@Scope(“prototype”) singleton:单例作用域,SPring容器中该类型的对象只有一个,无论获取多少次
优点:节省内存,缺点:不能做到个性化属性的赋值或修改 prototype:原型作用域:Spring容器中该类型的对象每获取一次,就会创建一个
新的对象返回 优点:能做到个性化属性的赋值或修改,缺点:占用内存过多
2、创建配置类(@Configuration和@ComponentScan(“Student所在的包路径”))
//表是当前类是配置Spring框架信息的
@Configuration
//指定组件扫描的包(当前包及其子包的所有类都会被扫描)
//如果被扫描的 类上有四大注解,那么这个类就会被实例化并保存到Spring容器
@ComponentScan("com.example.educationtest.demo")
public class StuConfig {
}
3、在测试类中初始化Spring容器并创建对象
@Test
void stuTest(){
AnnotationConfigApplicationContext acac =
new AnnotationConfigApplicationContext(StuConfig.class);
Student zhangsan = acac.getBean("student", Student.class);
zhangsan.setId(1);
zhangsan.setUsername("zhangsan");
zhangsan.setGender("男");
System.out.println(zhangsan);
}
二、实体类上不含有注解的(系统的、非自己定义的类)
1、创建实体类Teacher(没有@Component)
public class Teacher {
private Integer id;
private String username;
private String gender;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", username='" + username + '\'' +
", gender='" + gender + '\'' +
'}';
}
}
2、创建配置类(@Configuration)
在配置类中通过@Bean注解实例化对象
@Configuration
public class TchConfig {
@Bean
public Teacher teacher(){
Teacher tc1 = new Teacher();
tc1.setId(2);
tc1.setUsername("少珩");
tc1.setGender("男");
return tc1;
}
@Bean
public Date date(){
return new Date();
}
}
3、初始化Spring容器
@Test
void tchTest(){
AnnotationConfigApplicationContext acac =
new AnnotationConfigApplicationContext(TchConfig.class);
Teacher tc = acac.getBean("teacher", Teacher.class);
Date date = acac.getBean("date", Date.class);
System.out.println(tc);
System.out.println(date);
}
总结:仅自定义的类可以使用组件扫描的方式,当然自定义的类型也可以使用@Bean方法的做法,但是不推荐;
非自定义的类型不可以使用组件扫描的方式(因为你没有办法在这些类型上添加注解)只能使用@Bean方法的做法
控制反转:对象的创建和管理交给Spring容器
DI依赖注入
依赖注入:能够直接从Spring中获得拼装好的复杂对象的功能
依赖注入的两种形式
一:当类可以被注解修饰时
1、创建关羽类和青龙偃月刀类(两个类均被注解修饰)
@Component
public class GuanYu {
String name = "关羽";
//自动装配:默认按照类型装配
@Qualifier("dragonBlade")
@Autowired
//private DragonBlade dragonBlade;
private Weapon weapon;
public Weapon getWeapon() {
return weapon;
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void fight(){
System.out.println(name+"拿着"+weapon+"去战斗");
}
}
@Component
public class DragonBlade implements Weapon{
String name = "青龙偃月刀";
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
2、关羽类依赖青龙偃月刀采用@Autowired将青龙偃月刀自动装配给关羽
3、测试类中只需获取关羽,即可调用青龙偃月刀
@Test
void guanTest2(){
AnnotationConfigApplicationContext acac =
new AnnotationConfigApplicationContext(OuConfig.class);
GuanYu guanYu = acac.getBean("guanYu", GuanYu.class);
guanYu.fight();
}
二、当类中没有被注解修饰时
1.创建张飞和丈八蛇矛类
public class ZhangFei {
private String name = "张飞";
@Autowired
@Qualifier("snakeLance")
private SnakeLance snakeLance;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public SnakeLance getSnakeLance() {
return snakeLance;
}
public void setSnakeLance(SnakeLance snakeLance) {
this.snakeLance = snakeLance;
}
public void fight(){
System.out.println(name+"拿着"+snakeLance+"去战斗");
}
}
public class SnakeLance implements Weapon{
private String name = "丈八蛇矛";
@Override
public String toString() {
return name;
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2.创建配置类
@Configuration
@ComponentScan("com.example.educationtest.demo")
public class ZhangConfig {
@Bean
public SnakeLance snakeLance(){
return new SnakeLance();
}
@Bean
public SnakeLance snakeLance2(){
return new SnakeLance();
}
//@Bean标记的方法的参数列表如果声明了参数,Spring就会自动从SPring容器中寻找合适的对象,为这个参数赋值
//也就是说上面保存在容器中的snakelance对象就会自动赋值给参数sl,方法中又将sl赋值给zhangfei属性,所以实现了依赖注入
// @Bean
// public ZhangFei zhangFei(SnakeLance snakeLance){
// ZhangFei zhangFei = new ZhangFei();
// zhangFei.setSnakeLance(snakeLance);
// return zhangFei;
// }
}
3.在测试类中进行测试
@Test
void feiTest1(){
AnnotationConfigApplicationContext acac =
new AnnotationConfigApplicationContext(ZhangConfig.class);
ZhangFei zhangFei = acac.getBean("zhangFei", ZhangFei.class);
zhangFei.fight();
}
三、解耦
实现解耦的思路:
创建接口,炳然被依赖的类实现接口,即注入由之前具体类型修改为抽象类型,实现解耦
运行时会自动从spring容器中寻找接口类型对象来注入依赖,更换对象时只需更换保存在spring容器中的对象即可
1、创建接口
public interface Weapon {
String getName();
}
``
2`类中注入时发生的变化
![在这里插入图片描述](https://img-blog.csdnimg.cn/2d71a421414f446983e37a413f0efd76.png)
@Qulifier(“Bean对象”)当有对个Bean对象时指定唯一的一个作为注入的对象