先说业务场景,我在系统启动后想要维护一个List常驻内存,因为我可能经常需要查询它,但它很少更新,而且数据量不大,明显符合缓存的特质,但我又不像引入第三方缓存。现在的问题是,该List的内容是从数据库中查到的,那么如何实现在spring bean加载后(数据源这时已加载),才去初始化这个List呢?用@PostConstruct这个注解就好了,这是一个很有意思的注解,它是javax包里的注解,但spring却支持了它,其他这个注解的功能就类似于
@Bean(initMethod="init")
接下来看例子:
import com.crocodile.springboot.model.Merchant; import com.crocodile.springboot.repository.MerchantRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.util.ArrayList; import java.util.List; @Component public class MerchantList { @Autowired private MerchantRepository merchantRepository; private MerchantList() { } static class SingletonHolder { static MerchantList instance = new MerchantList(); } public static MerchantList getInstance() { return SingletonHolder.instance; } private static List<Merchant> merchants = new ArrayList<>(); @PostConstruct private void init() { merchants = (List<Merchant>) merchantRepository.findAll(); } public void addMerchant(Merchant merchant) { merchants.add(merchant); } public void deleteMerchant(Merchant merchant) { merchants.remove(merchant); } public List<Merchant> getMerchants() { return merchants; } }
我们既然使用了spring的初始化处理,那么就得让它发现不是?所以@Component是少不了的。Spring的Bean生命周期简单来说即:创建Bean->Bean的属性注入->Bean初始化->Bean销毁。我们结合上面的Bean来说,MerchantList这个bean先是被Spring容器创建,当然这里也会去创建MerchantRepository这个bean,容器统一管理所有的bean。接着MerchantRepository这个bean被注入到MerchantList这个bean,接着spring发现MerchantList有个初始化注解@PostConstruct就去执行了init方法。
@PostConstruct在Spring的CommonAnnotationBeanPostProcessor类中接受处理:
public CommonAnnotationBeanPostProcessor() { this.setOrder(2147483644); this.setInitAnnotationType(PostConstruct.class); this.setDestroyAnnotationType(PreDestroy.class); this.ignoreResourceType("javax.xml.ws.WebServiceContext"); }