文章目录
Bean的初始化和销毁
- 测试三种方式初始化bean
- 实现InitializingBean接口
- @Bean(initMethod = “init”, destroyMethod = “destroy”) 指定方法
- 成员方法使用 @PostConstruct @PreDestroy 注解实现
Java配置方式
package com.myron.springboot.study.beanlife.service;
public class BeanWayService {
public BeanWayService() {
System.out.println("BeanWayService--new BeanWayService()");
}
public void init() {
System.out.println("BeanWayService--init--@Bean(initMethod=)");
}
public void destroy() {
System.out.println("BeanWayService--destroy--@Bean(destroyMethod=)");
}
}
注解方式
package com.myron.springboot.study.beanlife.service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class AnnotationWayService {
public AnnotationWayService() {
System.out.println("AnnotationWayService--new AnnotationWayService()");
}
@PostConstruct
public void init() {
System.out.println("AnnotationWayService--init--init() use @PostConstruct");
}
@PreDestroy
public void destroy() {
System.out.println("AnnotationWayService--destroy--destroy() use @PreDestroy");
}
}
InitializingBean接口方式
package com.myron.springboot.study.beanlife.service;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class InterfaceWayService implements InitializingBean, DisposableBean {
public InterfaceWayService() {
System.out.println("InterfaceWayService--new InterfaceWayService()");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InterfaceWayService--InitializingBean");
}
@Override
public void destroy() throws Exception {
System.out.println("InterfaceWayService--DisposableBean");
}
}
配置三种方式Config
package com.myron.springboot.study.beanlife.config;
import com.myron.springboot.study.beanlife.service.AnnotationWayService;
import com.myron.springboot.study.beanlife.service.BeanWayService;
import com.myron.springboot.study.beanlife.service.InterfaceWayService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanLifeConfig {
// 实现InitializingBean接口
@Bean
public InterfaceWayService interfaceWayService() {
return new InterfaceWayService();
}
// java @bean配置 指定方法实现(等效于xml配置的init-method和destroy-method)
@Bean(initMethod = "init", destroyMethod = "destroy")
public BeanWayService beanWayService() {
return new BeanWayService();
}
// 方法使用 @PostConstruct @PreDestroy 注解实现
@Bean
public AnnotationWayService annotationWayService() {
return new AnnotationWayService();
}
}
运行测试
package com.myron.springboot.study.beanlife;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BeanLifeApplication {
public static void main(String[] args) {
System.out.println("-----------容器启动----------------------");
SpringApplication.run(BeanLifeApplication.class, args);
System.out.println("bean初始化顺序: 实例化对象[构造方法] --> 属性分配[依赖注入] --> 初始化[@PostConstruct/InitializingBean/@Bean(initMethod)]");
System.out.println("-----------容器关闭----------------------");
}
}
效果
搞个事情, 如果一个bean同时使用三种方式初始化bean,会怎么样呢
测试结果: 执行顺序@PostConstruct注解 -> InitializingBean接口 -> @Bean(initMethod)指定配置
补充
三种初始化和销毁方式,实际开发中怎么选呢
平常业务开发时候,不推荐InitializingBean和 DisposableBean接口。最好用另外两种
Spring 官方文档是这样说的
We recommend that you do not use the InitializingBean interface, because it unnecessarily couples the code to Spring. Alternatively, we suggest using the @PostConstruct annotation or specifying a POJO initialization method. (我们建议您不要使用 InitializingBean回调接口,因为它不必要地将代码耦合到 Spring。另外,我们建议使用@PostConstruct注解或指定bean定义支持的通用方法。)
InitializingBean 使用场景示例
发生时机,实例化对象[构造方法],属性分配[依赖注入] ,之后再到初始化,可以做一些定制化操作
场景1: RedisTeplate可选插件的默认初始化设置
如果没有配置自定义的序列化器, 使用默认的序列化器。
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
private boolean enableTransactionSupport = false;
private boolean exposeConnection = false;
private boolean initialized = false;
private boolean enableDefaultSerializer = true;
@Nullable
private RedisSerializer<?> defaultSerializer;
@Nullable
private ClassLoader classLoader;
@Nullable
private RedisSerializer keySerializer = null;
@Nullable
private RedisSerializer valueSerializer = null;
@Nullable
private RedisSerializer hashKeySerializer = null;
@Nullable
private RedisSerializer hashValueSerializer = null;
private RedisSerializer<String> stringSerializer = RedisSerializer.string();
@Nullable
private ScriptExecutor<K> scriptExecutor;
private final ValueOperations<K, V> valueOps = new DefaultValueOperations(this);
private final ListOperations<K, V> listOps = new DefaultListOperations(this);
private final SetOperations<K, V> setOps = new DefaultSetOperations(this);
private final ZSetOperations<K, V> zSetOps = new DefaultZSetOperations(this);
private final GeoOperations<K, V> geoOps = new DefaultGeoOperations(this);
private final HyperLogLogOperations<K, V> hllOps = new DefaultHyperLogLogOperations(this);
private final ClusterOperations<K, V> clusterOps = new DefaultClusterOperations(this);
public RedisTemplate() {
}
public void afterPropertiesSet() {
super.afterPropertiesSet();
boolean defaultUsed = false;
if (this.defaultSerializer == null) {
this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
}
if (this.enableDefaultSerializer) {
if (this.keySerializer == null) {
this.keySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.valueSerializer == null) {
this.valueSerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashKeySerializer == null) {
this.hashKeySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashValueSerializer == null) {
this.hashValueSerializer = this.defaultSerializer;
defaultUsed = true;
}
}
if (this.enableDefaultSerializer && defaultUsed) {
Assert.notNull(this.defaultSerializer, "default serializer null and not all serializers initialized");
}
if (this.scriptExecutor == null) {
this.scriptExecutor = new DefaultScriptExecutor(this);
}
this.initialized = true;
}
}
- 为什么不直接在构造方法或在属性定义时候直接初始化?(个人理解)
- 好处: 不仅可以让本类,指定自定义序列化方式, 同时子类可以很方便的修改选择默认的自定义序列化方式。比直接在构造方法中写,直观一些,也可以补充校验逻辑, 保证template类良好的扩展性。