Bean的生命周期

Bean和对象

Bean一定是对象,但是反过来不成立。

区别:

  1. Bean是由Spring创建的,而不是程序员手动创建的;

单例Bean

单例Bean并不是单例模式。

单例模式指的是,对于某个类,全局下只要一个实例对象;

但是单例Bean指的是,通过某个bean的名字获得的bean,是单例的,但是对于某个类,可以存在多个不同的Bean对象。

例如:

  1. @Component
  2. public class OrderService {
  3. }
  4. @Bean
  5. public OrderService orderService1() {
  6. return new OrderService();
  7. }
  8. @Bean
  9. public OrderService orderService2() {
  10. return enw OrderService();
  11. }
  12. // 以上三个会拿到三个OrderService的Bean
  13. System.out.println("orderService");
  14. System.out.println("orderService1");
  15. System.out.println("orderService2");

Bean创建的生命周期

假设我们有个UserService类, UserService类里有个OrderService的成员变量

  1. package com.example.firstspringboot.service;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.stereotype.Service;
  4. @Service
  5. public class UserService {
  6. @Autowired
  7. private OrderService orderService;
  8. public void test() {
  9. System.out.println("Test for UserService");
  10. }
  11. }
  1. package com.example.firstspringboot.service;
  2. import org.springframework.stereotype.Service;
  3. @Service
  4. public class OrderService {
  5. }

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); }

  1. - 如果没有无参的构造方法,会使用唯一的构造方法;
  2. ```java
  3. // 虽然没有无参构造方法,但存在唯一构造方法,就使用这个
  4. public UserService(OrderService orderService) {
  5. System.out.println(2);
  6. }
  • 如果没有无参的构造方法,但是有很多个带参数的构造方法,会报错。 ```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接口)

  1. 实现InitializingBean接口
  2. 重写afterPropertiesSet()方法

    public class UserService implements InitializingBean {
    
     public void afterPropertiesSet() throws Exception {
         xxxxx
     }
    }
    

spring是通过一下代码来做的:

if (userService instanceof InitializingBean) {
    userService.afterPropertiesSet();
}

初始化后(完成AOP)

在完成AOP以后,会生成一个动态代理对象,那么放入到容器中的对象就是该代理对象。

  1. 判断对象要不要进行AOP
  2. 怎么进行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);
    }
}