属性注入
package com.java.demo.service;
import org.springframework.stereotype.Service;
@Service
public class StudentService {
public int age = 20;
public void say() {
System.out.println("hello, StudentService: " + age);
}
}
Controller 类:
package com.java.demo.controller;
import com.java.demo.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller // 这个注解表示:当前这个类会自动地存储到 spring 中
public class StudentController {
@Autowired // 属性注入对象(从 spring 容器中更加简单的读取到对象)
private StudentService service;
public void say() {
System.out.println("hi,Controller");
service.say();
}
}
运行结果:
小结:
优点:方便简单
缺点:1. 没办法实现被 final 修饰的变量注入;2. 通用性不好,只适用于 IoC 容器中;3. 因为太简单了所以有些人会违背 spring 的 “单一设计” 原则。
Setter 注入
Controller 类:
package com.java.demo.controller;
import com.java.demo.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller // 这个注解表示:当前这个类会自动地存储到 spring 中
public class StudentController {
// @Autowired // 属性注入对象(从 spring 容器中更加简单的读取到对象)
// private StudentService service;
// 使用 Setter 注入
private StudentService service;
@Autowired
public void setService(StudentService service) {
this.service = service;
}
public void say() {
System.out.println("hi,Controller");
service.say();
}
}
运行结果:
小结:
优点:符合单一设计原则(一个方法只能传递一个对象)
缺点:1. 依旧存在没办法实现被 final 修饰的变量注入;2. 使用 Setter 注入的对象可能会被修改。(代码本来是 20 的,通过 set 的传参可能被改成了 别的数)
构造方法注入
Controller 类:
如果当前的类中只有一个构造方法,那么 @Autowired 可以省略
package com.java.demo.controller;
import com.java.demo.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller // 这个注解表示:当前这个类会自动地存储到 spring 中
public class StudentController {
// @Autowired // 属性注入对象(从 spring 容器中更加简单的读取到对象)
// private StudentService service;
// // 使用 Setter 注入
// private StudentService service;
//
// @Autowired
// public void setService(StudentService service) {
// this.service = service;
// }
// 使用 构造方法注入
private StudentService service;
// @Autowired
public StudentController(StudentService service) {
this.service = service;
}
public void say() {
System.out.println("hi,Controller");
service.say();
}
}
运行结果:
小结:
优点:1. 实现了被 final 修饰的变量也可以注入了;2. 注入的对象不会被改变(构造方法只执行一次);3. 可以保证注入对象完全初始化;4. 通用性更好(即放在不是 IoC 框架中也能用)。
为什么这里可以注入一个不可变对象?因为在 Java 中,被 final 修饰的对象必须要满足这两个条件中的一个:final 修饰的对象要么直接赋值,要么在构造方法中赋值。
这个 spring 官方推荐的写法,所以就没有缺点(狗头.jpg)。但是官方好像也是用的第一种注入,因为太简单方便了。
@Resource
这是除了 @Autowired 之外,另外一种也可以做到类注入的方式。
@Autowired 和 @Resource 的区别
1. @Autowired 来⾃于 Spring,@Resource 来⾃于 JDK 的注解
2. @Resource 只能⽤于 Setter 注⼊和属性注⼊,不能⽤于构造函数注⼊。
3. @Resource ⽀持更多的参数设置,例如可以设置 name,然后根据 name 获取 Bean。
4. @Autowired 是先根据类型查找,类型相同后再根据名称查找;@Resource 则恰好反过来。(在 spring 容器中找 Bean 的方式是 根据类型查找、根据名称查找)
比如:同一个类型存了多个 Bean
一个 User 类存了两个:
package com.java.demo.component;
import com.java.demo.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
@Controller
public class UserBeans {
@Bean
public User getUser() {
User user = new User();
user.setUid(1);
user.setName("张三");
user.setPassword("123456");
return user;
}
@Bean
public User getUser2() {
User user = new User();
user.setUid(2);
user.setName("李四");
user.setPassword("123456");
return user;
}
}
运行时发现:
报错的原因是: 同一个类型存了多个 Bean 对象,导致不知道要找哪个。
解决:使用 @Resource 设置 name 属性: