目录
Spring是一个包含众多工具的IoC容器(容器中装的是对象)
Spring两大核心思想:IoC、AOP【重要面试题!!】
IoC(Inversion of Control) 翻译成中⽂是“控制反转”的意思,即控制权反转,将创建对象的控制权,交给了Spring(优点:解耦)
Spring帮我们管理对象
①告诉Spring,帮我们管理哪些对象【存】
②知道如何取出来这些对象【取】(DI)
也就是说学 Spring 最核⼼的功能,就是学如何将对象存⼊到 Spring 中,再从 Spring 中获取对象的过 程。
Spring 是⼀个 IoC 容器,说的是对象的创建和销毁的权利都交给 Spring 来管理了,它本身⼜具备了存 储对象和获取对象的能⼒。
(将对象存放到容器中的好处:将对象存储在 IoC 容器相当于将以后可能⽤的所有⼯具制作好都放到仓 库中,需要的时候直接取就⾏了,⽤完再把它放回到仓库。⽽ new 对象的⽅式相当于,每次需要⼯具 了,才现做,⽤完就扔掉了也不会保存,下次再⽤的时候还得重新做,这就是 IoC 容器和普通程序开 发的区别。)
DI(Dependency Injection)依赖注入
所谓依赖注⼊,就是由 IoC 容器在运⾏期间,动态地将某种依赖关系注⼊到对象之中。所以,依 赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过引⼊ IoC 容 器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。 IoC 是“⽬标”也是⼀种思想,⽽⽬标和思想只是⼀种指导原则,最终还是要有可⾏的落地⽅案,⽽ DI 就 属于具体的实现。
⽐如说我今天⼼情⽐较好,吃⼀顿好的犒劳犒劳⾃⼰,那么“吃⼀顿好的”是思想和⽬标(是 IoC), 但最后我是吃海底捞还是杨国福?这就是具体的实现,就是 DI。
Bean
在 Java 语⾔中对象也叫做 Bean
一、添加注解存储 Bean 对象
想要将对象存储在 Spring 中,有两种注解类型可以实现:
①类注解:@Controller(控制器存储) @Service(服务存储) @Repository(仓库存储) @Component(组件存储) @Configuration(配置存储) 【五大注解】
②方法注解:@Bean
1)类注解
@Controller // 将对象存储到 Spring 中
public class UserController {
public void sayHi(String name) {
System.out.println("Hi," + name);
}
}
此时我们先使⽤之前读取对象的⽅式来读取上⾯的 UserController 对象
public class Application {
public static void main(String[] args) {
// 1.得到 spring 上下⽂
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
// 2.得到 bean
UserController userController = (UserController)
context.getBean("userController");
// 3.调⽤ bean ⽅法
userController.sayHi("Bit");
}
}
既然功能是⼀样的,为什么需要这么多的类注解呢?
原因是让程序员看到类注解之后,就能直接了解当前类 的⽤途,⽐如: @Controller:表示的是业务逻辑层; @Servie:服务层; @Repository:持久层; @Configuration:配置层。
查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:
这些注解⾥⾯都有⼀个注解 @Component,说明它们本身就是属于 @Component 的“⼦类”。
注意 Bean 的命名
如果第一个字母和第二个字母都为大写,则不变;其他情况则将首字母小写
2)方法注解@Bean
放在方法上,并且⽅法注解 @Bean 要配合类注解才能将对象正常的存储到 Spring 容器中
@Component
public class User {
@Bean
public User user1() {
User user = new User();
user.setId(1);
user.setName("Java");
return user;
}
}
public class Application {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
User user = (User) context.getBean(User.class);//通过类型获取对象,只适用于一个类型存在一个bean时
User user = (User) context.getBean("user1");//通过方法名来获取
User user = (User) context.getBean("user1",User.class);//通过方法名和类名来获取
System.out.println(user.toString());
}
}
@Bean传递参数
重命名 Bean
使用@Bean注解时,benan的名称默认是方法名
可以通过设置 name 属性给 Bean 对象进⾏重命名操作
@Component
public class Users {
@Bean(name = {"u1"})
public User user1() {
User user = new User();
user.setId(1);
user.setName("Java");
return user;
}
}
class App {
public static void main(String[] args) {
// 1.得到 spring 上下⽂
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
// 2.得到某个 bean
User user = (User) context.getBean("u1");
// 3.调⽤ bean ⽅法
System.out.println(user);
}
}
这个重命名的 name 其实是⼀个数组,⼀个 bean 可以有多个名字,并且 name={} 可以省略
@Bean({"u1", "us1"})
public User user1() {
User user = new User();
user.setId(1);
user.setName("Java");
return user;
}
二、添加注解获取 Bean 对象(对象装配)
获取 bean 对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注⼊。
对象装配(对象注⼊)的实现⽅法以下 3 种:
1. 属性注⼊ 2. 构造⽅法注⼊ 3. Setter 注⼊
下⾯我们按照实际开发中的模式,将 Service 类注⼊到 Controller 类中。
①属性注入
使⽤ @Autowired 实现
属性注入以类型进行匹配,与注入的属性名称无关,但一个类型存在多个对象时,优先名称·匹配,如果名称匹配不上,那就报错)
@Service
public class UserService {
public User getUser(Integer id){
User user=new User();
user.setId(id);
user.setName("Java-"+id);
return user;
}
}
@Controller
public class UserController {
//属性注入
@Autowired
private UserService userService;
public User getUser(Integer id){
return userService.getUser(id);
}
}
public class App {
public static void main(String[] args) {
//1.得到Spring上下文对象
ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
//2.加载某个bean
UserController userController=context.getBean(UserController.class);
//3.调用相应方法
System.out.println(userController.getUser(1).toString());
}
}
②构造方法注入
在类的构造⽅法中实现注⼊
@Controller
public class UserController2 {
// 注⼊⽅法2:构造⽅法注⼊
private UserService userService;
@Autowired
public UserController2(UserService userService) {
this.userService = userService;
}
public User getUser(Integer id) {
return userService.getUser(id);
}
}
③Setter 注⼊
@Controller
public class UserController3 {
// 注⼊⽅法3:Setter注⼊
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public User getUser(Integer id) {
return userService.getUser(id);
}
}
三种注⼊优缺点分析【常见面试题】
属性注⼊
优点:简洁,使⽤⽅便;
缺点: ①只能⽤于IoC容器,如果是⾮IoC容器不可⽤,并且只有在使⽤的时候才会出现NPE(空指 针异常) ②不能注⼊⼀个Final修饰的属性
构造函数注⼊
优点:①可以注⼊final修饰的属性 ②注⼊的对象不会被修改
依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法 是在类加载阶段就会执⾏的⽅法. ③通⽤性好,构造⽅法是JDK⽀持的,所以更换任何框架,他都是适⽤的
缺点: 注⼊多个对象时,代码会⽐较繁琐
Setter注⼊
优点:⽅便在类实例之后,重新对该对象进⾏配置或者注⼊
缺点:①不能注⼊⼀个Final修饰的属性 ②注⼊对象可能会被改变,因为setter⽅法可能会被多次调⽤,就有被修改的⻛险.
关于
@Autowired注解的省略
①在属性上进行注入时,必须使用
@Autowired
注解。②如果一个类只有一个构造函数,并且这个构造函数是默认的(没有参数),可以省略③
@Autowired
注解,Spring Boot会自动识别这个构造函数进行注入如果类中有一个或多个Setter方法,并且这些方法只有一个参数,那么也可以省略
@Autowired
注解
除了可以使⽤ @Autowired 关键字之外,我们还可以使⽤ @Resource 进⾏注⼊
@Controller
public class UserController {
// 注⼊
@Resource
private UserService userService;
public User getUser(Integer id) {
return userService.getUser(id);
}
}
@Autowired 和 @Resource 的区别
出身不同:@Autowired 来⾃于 Spring,⽽ @Resource 来⾃于 JDK 的注解;
使⽤时设置的参数不同:相⽐于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如 name 设置,根据名称获取 Bean。
当出现以下多个 Bean,返回同⼀对象类型时程序会报错
@Component
public class Users {
@Bean
public User user1() {
User user = new User();
user.setId(1);
user.setName("Java");
return user;
}
@Bean
public User user2() {
User user = new User();
user.setId(2);
user.setName("MySQL");
return user;
}
}
@Controller
public class UserController4 {
// 注⼊
@Resource
private User user;
public User getUser() {
return user;
}
}
如何解决??
①使⽤ @Resource(name="user1") 定义
@Controller
class UserController4 {
// 注⼊
@Resource(name = "user1")
private User user;
public User getUser() {
return user;
}
}
②使⽤ @Qualifier 注解定义名称。
在@Qualifier的value属性中,指定注⼊的bean 的名称,指定当前要注⼊的bean对象
@Controller
public class UserController5 {
// 注⼊
@Autowired
@Qualifier(value = "user2")
private User user;
public User getUser() {
return user;
}
}
@Qualifier注解不能单独使⽤,必须配合@Autowired使⽤
③@Primary确定默认实现
@Component
public class BeanConfig {
@Primary //指定该bean为默认bean的实现
@Bean("u1")
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;
}
}
常⻅⾯试题:@Autowird与@Resource的区别
• @Autowired是spring框架提供的注解,⽽@Resource是JDK提供的注解
• @Autowired默认是按照类型注⼊,⽽@Resource是按照名称注⼊.相⽐于@Autowired来说, @Resource⽀持更多的参数设置,例如name设置,根据名称获取Bean。
面试题
常⻅注解有哪些?分别是什么作⽤?
weburl映射:@RequestMapping
参数接收和接⼝响应:@RequestParam,@RequestBody,@ResponseBody bean的存储:@Controller,@Service,@Repository,@Component,@Configuration, @Bean
bean的获取:@Autowired,@Qualifier,@Resource