Bean的生命周期
Bean和对象
Bean一定是对象,但是反过来不成立。
区别:
- Bean是由Spring创建的,而不是程序员手动创建的;
单例Bean
单例Bean并不是单例模式。
单例模式指的是,对于某个类,全局下只要一个实例对象;
但是单例Bean指的是,通过某个bean的名字获得的bean,是单例的,但是对于某个类,可以存在多个不同的Bean对象。
例如:
@Component
public class OrderService {
}
@Bean
public OrderService orderService1() {
return new OrderService();
}
@Bean
public OrderService orderService2() {
return enw OrderService();
}
// 以上三个会拿到三个OrderService的Bean
System.out.println("orderService");
System.out.println("orderService1");
System.out.println("orderService2");
Bean创建的生命周期
假设我们有个UserService类, UserService类里有个OrderService的成员变量
package com.example.firstspringboot.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private OrderService orderService;
public void test() {
System.out.println("Test for UserService");
}
}
package com.example.firstspringboot.service;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
}
UserService类 -> 推断构造方法 -> 生成对象 ->依赖注入 -> Bean
通过无参构造方法生成的对象中,orderService是没有值的,因为没有地方对其进行初始化,但是经过了依赖注入以后,生成的Bean中就有值了。
推断构造方法
- 如果有无参构造方法,会去使用无参的构造方法; ```java // 会用无参构造方法 public UserService() { System.out.println(1); }
public UserService(OrderService orderService) { System.out.println(2); }
public UserService(OrderService orderService, OrderService orderService2) { System.out.println(3); }
- 如果没有无参的构造方法,会使用唯一的构造方法;
```java
// 虽然没有无参构造方法,但存在唯一构造方法,就使用这个
public UserService(OrderService orderService) {
System.out.println(2);
}
- 如果没有无参的构造方法,但是有很多个带参数的构造方法,会报错。 ```java public UserService(OrderService orderService) { System.out.println(2); }
public UserService(OrderService orderService, OrderService orderService2) { System.out.println(3); }
// Spring迷糊了,不知道用哪个
- 可以通过注解的方式告诉Spring用哪个构造方法
```java
public UserService(OrderService orderService) {
System.out.println(2);
}
// 使用注解,Spring就知道用哪个了
@Autowired
public UserService(OrderService orderService, OrderService orderService2) {
System.out.println(3);
}
调用有参构造函数时,对象的值哪来的?
从Spring容器中获取的,Spring容器可以看成一个Map
Map
Spring首先会通过类型去找对应的对象,可能会找到多个。然后通过名字来找唯一的那一个。因此名字错误就可能找不到,就会报错。
如下, 如果有三个OrderService实例,名字分别为orderService, orderService1, orderService2;
// 通过类型可以找到3个
// 通过名字,一个都匹配不到
// 因此会报错
public UserService(OrderService orderService123) {
this.orderService = orderService123;
}
对于上面的例子,如果只有一个OrderService实例,那么就不会报错,因为通过类型能找到唯一的那一个进行注入。
依赖注入
这一步就是给对象里的属性赋值,即如果属性是对象,那么就去Bean容器里找对应的对象,进行赋值。如果该对象还没有称为Bean,那么就会先去创建它的Bean然后进行赋值。
从依赖注入到Bean
从依赖注入到生成Bean的过程又包括以下几步:
依赖注入 -> 初始化前 (@PostConstruct )-> 初始化中 (InitializingBean) -> 初始化后(AOP) -> Bean
初始化前(@PostConstruct)
@PostConstruct用在初始化Bean前,例如我们在UserService里有一个User admin, 我们希望Spring帮我们调用一个方法做admin的初始化,就在这个方法前添加@PostConstruct即可
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Autowired
private User admin;
@PostConstruct
public void initAdmin() {
this.admin.setName("admin1");
}
public void test() {
System.out.println("Test for UserService");
}
}
初始化中(实现InitializingBean接口)
- 实现InitializingBean接口
重写afterPropertiesSet()方法
public class UserService implements InitializingBean { public void afterPropertiesSet() throws Exception { xxxxx } }
spring是通过一下代码来做的:
if (userService instanceof InitializingBean) {
userService.afterPropertiesSet();
}
初始化后(完成AOP)
在完成AOP以后,会生成一个动态代理对象,那么放入到容器中的对象就是该代理对象。
- 判断对象要不要进行AOP
- 怎么进行AOP
如何进行AOP
Step 1:生成代理类对象
- 继承要代理的类,
- 然后重写要增强的方法。
- 在增强的方法中,首先执行切面的逻辑
然后执行被代理的方法 ```java class UserServiceProxy extends UserService {
//尽管UserService对象中的OrderService对象有值; // 但是代理对象中的orderService没有值 // 因为对于代理对象,没有做依赖注入这一步。
private OrderService orderService;
// 为了防止属性没有初始化这一问题的出席,将被代理的对象注入进来。
private UserService target;
public void test() {
// 执行切面的逻辑
// 执行被代理的方法
// 不能单纯通过super.test();来调用父类的方法,因为代理对象中的某些属性没有值,
// 那么调用super.test();也就会空指针异常。
target.test();
}
}
<a name="m3y1L"></a>
#### AOP事务
如果Test方法是和数据库事务相关,则:
```java
class UserServiceProxy extends UserService {
//尽管UserService对象中的OrderService对象有值;
// 但是代理对象中的orderService没有值
// 因为对于代理对象,没有做依赖注入这一步。
private OrderService orderService;
// 为了防止属性没有初始化这一问题的出席,将被代理的对象注入进来。
private UserService target;
public void test() {
// 0.首先判断test方法上有没有@Transaction
// 1. 利用事务管理器建立一个数据库连接conn
// 2. conn.autocommit = false
// 3. 执行被代理的方法
target.test();
// conn.commit(); 或者 rollback();
}
}
如何手写代码,判断某个属性上加了@Autowired
反射:
UserService userService = application.context.getBean("userService", UserService.class);
for (Field field : userService.getClass().getFields()) {
if (field.isAnnotationPresent(AutoWired.class)) {
field.set(userService, xxx);1
}
}
如何手写代码,判断某个属性上加了@PostConstruct
同样是通过反射
for (Method method : userService.getClass().getMethods()) {
if (method.isAnnotationPresent(PostConstruct.class)) {
method.invoke(userService, null);
}
}