|
目录一、Bean生命周期的五个阶段Bean的初始化二、@PostConstruct和@PreDestroy各自的效果三、 实例化和初始化的区别四、为什么要先设置属性在进⾏初始化呢?一、Bean生命周期的五个阶段Java中的公共类称之为Bean或JavaBean,而Spring中的Bean指的是将对象的生命周期,交个SpringIoC容器来管理的对象。所以Spring中的Bean对象在使用时,无需通过new来创建对象,只需要通过DI(依赖注入),从Spring中取出要使用的对象即可。Bean作为一个Java对象,具有一定的生命周期。它的生命周期包括以下几个阶段:实例化:在Java应用程序中,Bean对象是通过new关键字或者反射机制来实例化的。在这个阶段,Bean对象被创建,并分配了内存空间。设置属性(Bean注入和装配)初始化:当Bean对象被创建后,需要进行初始化,包括设置属性值、执行一些初始化操作等。在Spring框架中,Bean的初始化可以通过配置文件中的init-method属性进行指定。使用:在Bean初始化之后,它就可以被应用程序使用了。在使用过程中,Bean可能会调用其他对象的方法,从而导致其他Bean对象被实例化和初始化。销毁:当Bean对象不再被使用时,应该将其销毁并释放占用的内存空间。在Spring框架中,Bean的销毁可以通过配置文件中的destroy-method属性进行指定。总的来说,Bean对象的生命周期可以通过实例化、初始化、使用和销毁这几个阶段来描述。在Spring框架中,Bean的生命周期还可以通过BeanPostProcessor接口来进行扩展和定制。为了便于理解 我们引用一个现实中的事件来形容 Bean的⽣命流程看似繁琐,但咱们可以以⽣活中的场景来理解它,⽐如我们现在需要买⼀栋房⼦,那么我们的流程是这样的:1.先买房(实例化,从⽆到有);2.装修(设置属性);3.买家电,如洗⾐机、冰箱、电视、空调等([各种]初始化);4.⼊住(使⽤Bean);5.卖出去(Bean销毁)。 Bean的初始化执行各种通知(BeanNameAware、BeanFactoryAware)等接口方法初始化的前置方法(PostConstruct)初始化方法初始化的后置方法(PreDestroy)下面用代码演示整个Bean的生命周期:我们用构造方式来展示实例化的效果,实例化和属性设置是Java级别的系统“事件”,其操作过程不可⼈⼯⼲预和修改 所以下面没有演示设置属性packagecom.example.bean.test;importorg.springframework.beans.factory.BeanNameAware;importorg.springframework.stereotype.Component;importjavax.annotation.PostConstruct;importjavax.annotation.PreDestroy;@ComponentpublicclassBeanLifeComponentimplementsBeanNameAware{privateStringname;publicBeanLifeComponent(){System.out.println("实例化方法执行拉");}publicvoidsetBeanName(Strings){System.out.println("执行BeanName的通知方法");}@PostConstructpublicvoidpostConstruct(){System.out.println("初始化方法执行");}publicvoiduse(){System.out.println("使用Bean");}@PreDestroypublicvoidpreDestroy(){System.out.println("销毁方法执行");}}因为初始化的前置方法和后置方法是为所有Bean服务的,而非为某一个Bean服务的,所以这两个方法不能写在某个具体的Bean中,否则(这两个方法)不会执行。 所以我们另外创建一个类来实现这两个方法packagecom.example.bean.test;importorg.springframework.beans.BeansException;importorg.springframework.beans.factory.config.BeanPostProcessor;importorg.springframework.stereotype.Component;@ComponentpublicclassMyBeanPostProcessorimplementsBeanPostProcessor{@OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{if(beanName.equals("beanLifeComponent")){System.out.println("初始化前置方法执行");}returnbean;}@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{if(beanName.equals("beanLifeComponent")){System.out.println("初始化后置方法执行");}returnbean;}} 在得到上下文对象这里 因为我们是使用springboot演示的所以我们使用ConfigurableApplicationContext来得到上下文对象packagecom.example.bean.test;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.context.ConfigurableApplicationContext;@SpringBootApplicationpublicclassDemoApplication{publicstaticvoidmain(String[]args){//得到上下文对象,并启动SpringBoot项目ConfigurableApplicationContextcontext=SpringApplication.run(DemoApplication.class,args);//获取BeanBeanLifeComponentcomponent=context.getBean(BeanLifeComponent.class);//使用Beancomponent.use();//停止SpringBoot项目context.close();}}结果如下: 二、@PostConstruct和@PreDestroy各自的效果当Bean被容器初始化之后,会调用@PostConstruct的注解方法。当Bean在容器销毁之前,调用被@PreDestroy注解的方法代码如下:所以,PostConstruct注释用于在依赖关系注入完成之后需要执行的方法上,以执行任何初始化。此方法必须在将类放入服务之前调用。支持依赖关系注入的所有类都必须支持此注释。即使类没有请求注入任何资源,用PostConstruct注释的方法也必须被调用。只有一个方法可以用此注释进行注释。@PostConstructpublicvoiddoPostConstruct(){System.out.println("执行了新版本@PostConstruct前置初始化方法");}@PreDestroypublicvoiddoPreDestroy(){System.out.println("执行新版本@PreDestroy销毁方法");}PreDestroy用与在依赖注入完成之前的方法前面执行,遵守准则:该方法不得有任何参数该方法的返回类型必须为void;该方法不得抛出已检查异常;应用PostConstruct的方法可以是public、protected、packageprivate或private;该方法不能是static;该方法可以是final;该方法只会被执行一次三、 实例化和初始化的区别实例化和属性设置是Java级别的系统“事件”,其操作过程不可⼈⼯⼲预和修改;⽽初始化是给开发者提供的,可以在实例化之后,类加载完成之前进⾏⾃定义“事件”处理。四、为什么要先设置属性在进⾏初始化呢?仔细观察下面代码ServicepublicclassUserService{publicUserService(){System.out.println("调⽤UserService构造⽅法");}publicvoidsayHi(){System.out.println("UserServiceSayHi.");}}@ControllerpublicclassUserController{@ResourceprivateUserServiceuserService;@PostConstructpublicvoidpostConstruct(){userService.sayHi();System.out.println("执⾏UserController构造⽅法");}}我们可以发现很是为了避免空指针异常。
|
|