@PostConstruct、构造函数和@AutoWired的执行顺序

很久之前使用了@PostConstruct注解,用来注入一些程序中需要的服务。时间久了,迷迷糊糊的不知道当时的使用场景是什么了。最近又遇到一个场景,赶紧整理一下。

填坑前奏:

在维护一个旧程序时,在某个类中,前一任攻城狮 写了一段这样的代码:

public class AService { 
  static Map<String, String> brandType = new HashedMap();
  static Map<String, String> channelType = new HashedMap();

  static {
    brandType.put("1", "ABCD");
    brandType.put("2", "EFGH");
    ……
    //N个配置
  }

  public …… FuncB(){
	//举个栗子
	String typeCode = brandType.getCode;
  }
}

单从语法上,上面这段代码没有什么错误,但如果我们需要为其中一个类别的map中添加或者修改方式,难道我们将线上机器停止,修改代码、重新打包、然后部署??岂不荒谬,终究会把自己埋在坑里,不能自拔。

于是小编将这些方式的配置信息存储到mysql数据库中,通过不同的类别来获取。由于当前类中的其他方法还需要使用当前map中的值,所以小编考虑将dao的获取使用@PostConstruct的方式来获取。

public class AService {
    @Autowired(required = false)
    private MetaConfigDao configDao;

    Map<String,String> brandType = new HashedMap();
    Map<String,String> channelType = new HashedMap();

    @PostConstruct
    public void initConfigs() {
        brandType = configDao.queryConfigsByType("brand")
			.stream()
            .collect(Collectors.toMap(MetaConfigEntity::getCode,MetaConfigEntity::getName));
        channelType = configDao.queryConfigsByType("channel")
            .stream()
            .collect(Collectors.toMap(MetaConfigEntity::getCode,MetaConfigEntity::getName));
        ……
    }

	public …… FuncB(){
		//举个栗子
		String typeCode = brandType.getCode;
	}
}

“知其然,知其所以然”,我们使用一个test类来测试一下 类的构造方法、postContruct、autoWired的执行顺序;

▶ 基础扫盲

使用@PostConstruct注解修饰的方法会在服务器加载Servlet时运行,并且只会执行一次,在构造函数之后,在init方法之前执行;

借用网上的一个图片,执行顺序为:

执行顺序

▶实践出真知

为了验证上述的顺序,我们通过一个测试类来演示一下:

@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class PersonalTest {

  @Autowired
  private CrowdService crowdService;

  public PersonalTest(){
    System.out.println("构造器,此时crowService还没有被注入=" + crowdService);
  }

  @PostConstruct
  private void init(){
    System.out.println("此时crowdSrevice在依赖注入后将被自动调用,crowdService=" + crowdService);
  }
  @Test
  public void test() throws Exception{
  }
}

我们运行test()方法,打印的日志为:

构造器,此时crowService还没有被注入=null  //执行的第一句日志就是该类的构造方法

………………………………………………//此处为springBoot程序打印的日志

此时crowdSrevice在依赖注入后将被自动调用,crowdService=**.*****.***.CrowdService@2128762

为了验证 PostContruct注解所修饰的变量/方法只加载一次,我们在上述类中添加另外一个测试方法:test2();

  @Test
  public void test2() throws Exception{
    System.out.println("------前------");
    PersonalTest test = new PersonalTest();
    System.out.println("------后------");
  }

执行的结果为:

构造器,此时crowService还没有被注入=null  //执行的第一句日志就是该类的构造方法

………………………………………………//此处为springBoot程序打印的日志

此时crowdSrevice在依赖注入后将被自动调用,crowdService=**.*****.***.CrowdService@2128762
------前------
构造器,此时crowService还没有被注入=null
------后------

我们可以发现,当我们对类执行new操作时,该类的构造方法会再次被执行,但是PostContruct却没有再次执行。但是crowdService中依旧有值。

 

@PostConstruct构造函数都是在Servlet加载时调用的方法,但它们之间有一些区别。 首先,构造函数是在对象创建时调用的,用于初始化对象的状态。构造函数定义了对象的属性和行为,并可以接受参数。构造函数在对象创建时被调用,因此它是首先被执行的。 而@PostConstruct注解是一种在对象创建后,依赖注入完成后执行的方法。它被用来标记一个方法,在对象的所有依赖关系都被注入后,执行一些初始化操作。@PostConstruct方法在构造函数执行后被调用,因此它是构造函数执行完毕后被执行的。 当@PostConstruct、@Autowired构造函数在同一个类中时,它们的执行顺序是:构造函数 -> @Autowired -> @PostConstruct。也就是说,首先执行构造函数,然后进行依赖注入,最后执行@PostConstruct注解标记的方法[2]。 当@PostConstruct、@Autowired构造函数在不同的类中时,它们的执行顺序是:构造函数 -> @Autowired -> @PostConstruct。同样地,首先执行构造函数,然后进行依赖注入,最后执行@PostConstruct注解标记的方法。此时,@PostConstruct注解只会在第一次创建实例时被调用,之后的实例创建过程中将不再执行。 总结起来,构造函数用于对象的初始化,而@PostConstruct注解用于对象依赖注入完成后的初始化操作。它们在执行顺序和作用上有所区别。 引用 引用 引用[3
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值