spring中afterPropertiesSet方法与init-method配置描述

---恢复内容开始---

今天看了前辈们写的代码用到了afterPropertiesSet()的方法,就好好整理了spring的bean加载

1. InitializingBean.afterPropertiesSet()

Spring中InitializingBean接口类为bean提供了定义初始化方法的方式,它仅仅包含一个方法:afterPropertiesSet()。
Bean实现这个接口,在afterPropertiesSet()中编写初始化代码:

  1 public class AlarmQueue<T> implements InitializingBean, DisposableBean, Component {
  2     private static final CLogger logger = Utils.getLogger(AlarmQueue.class);
  3 
  4     @Autowired
  5     ThreadFacade thf;
  6     @Autowired
  7     private CloudBus bus;
  8 
  9     private RedisTemplate redisTemplate;
 10     private String key;
 11     private RedisConnectionFactory factory;
 12     private RedisConnection connection;
 13     private Lock lock = new ReentrantLock();//基于底层IO阻塞考虑
 14     private Thread alarmThread;
 15     private boolean isInit = true;
 16     private boolean isClosed;
 17 
 18     public void setRedisTemplate(RedisTemplate redisTemplate) {
 19         this.redisTemplate = redisTemplate;
 20     }
 21 
 22     public void setKey(String key) {
 23         this.key = key;
 24     }
 25 
 26     @Override
 27     public void afterPropertiesSet() throws Exception {//
 28         logger.info("============== afterPropertiesSet =================");
 29         factory = redisTemplate.getConnectionFactory();
 30         connection = RedisConnectionUtils.getConnection(factory);
 31         alarmThread = new AlarmThread();
 32         alarmThread.setDaemon(true);
 33         alarmThread.start();
 34     }
 35 
 36     class AlarmThread extends Thread {
 37         @Override
 38         public void run() {
 39             try {
 40                 if (isInit) {
 41                     Thread.sleep(30000);
 42                     isInit = false;
 43                 }
 44 
 45                 logger.info("============== AlarmThread Start =================");
 46                 while (true) {
 47                     T value = takeFromTail(0);
 48                     if (value != null) {
 49                         try {
 50                             // listener.onMessage(value);
 51                             HandleAlarmMsg amsg = new HandleAlarmMsg();
 52                             amsg.setAlarmValue(value.toString());
 53                             bus.makeTargetServiceIdByResourceUuid(amsg, AlarmConstant.SERVICE_ID_ALARM_LOG, Platform.getUuid());
 54                             bus.send(amsg);
 55                         } catch (Exception e) {
 56                             logger.error(String.format("fail to handle alarm!Alarm content: %s, Error: %s", value.toString(), e.getMessage()));
 57                         }
 58                     }
 59                 }
 60             } catch (InterruptedException e) {
 61                 throw new RuntimeException(String.format("Alarm thread InterruptedException! Error: %s", e.getMessage()));
 62             }
 63         }
 64     }
 65 
 66     public T takeFromTail(int timeout) throws InterruptedException {
 67         lock.lockInterruptibly();
 68         try {
 69             List<byte[]> results = connection.bRPop(timeout, key.getBytes());
 70             if (CollectionUtils.isEmpty(results)) {
 71                 return null;
 72             }
 73             return (T) redisTemplate.getValueSerializer().deserialize(results.get(1));
 74         } catch (Exception e) {
 75             throw new RuntimeException(String.format("fail to take value from queue %s! Error: ", this.key, e.getMessage()));
 76         } finally {
 77             lock.unlock();
 78         }
 79     }
 80 
 81     @Override
 82     public void destroy() throws Exception {
 83         if (isClosed) {
 84             return;
 85         }
 86         shutdown();
 87         RedisConnectionUtils.releaseConnection(connection, factory);
 88         isClosed = true;
 89     }
 90 
 91     private void shutdown() {
 92         AlarmThread.interrupted();
 93     }
 94 
 95     @Override
 96     public boolean start() {
 97         return true;
 98     }
 99 
100     @Override
101     public boolean stop() {
102         return true;
103     }
104 }

在xml配置文件中并不需要对bean进行特殊的配置,Spring在在配置文件完成该bean的所有赋值后,会检查该bean是否实现了InitializingBean接口,如果实现就调用bean的afterPropertiesSet方法。

2. init-method配置

Spring虽然可以通过InitializingBean完成一个bean初始化后调用这个bean自定义方法,但是这种方式要求bean实现InitializingBean接口。一但bean实现了InitializingBean接口,那么这个bean的代码就和Spring耦合到一起了。可以使用Spring提供的init-method的功能来执行一个bean自定义的初始化方法。
以下代码中,类MonitorKafka不实现任何Spring的接口,定义一个没有参数的方法monitorKafkaMsg()。

 1 public class AlarmLogManagerImpl extends AbstractService implements ApiMessageInterceptor {
 2 
 3     private static final CLogger logger = Utils.getLogger(AlarmLogManagerImpl.class);
 4     @Autowired
 5     private CloudBus bus;
 6     @Autowired
 7     private DatabaseFacade dbf;
 8     @Autowired
 9     private ThreadFacade thf;
10     @Autowired
11     private RESTFacade restf;
12     @Autowired
13     private SmsService smsService;
14     @Autowired
15     private MailService mailService;
16 
17   ....  
18 }
<bean id="AlarmLogManager" class="com.syscxp.alarm.log.AlarmLogManagerImpl"init-method="AlarmLogManager" destroy-method="destroy"> 
....
</bean>

注:destroy-method是该bean销毁前调用指定的方法。
init-method配置中的monitorKafkaMsg()方法将会在该bean初始化完成后被调用,Spring要求init-method是一个无参数的方法,否则会抛出异常,Spring将中止这个Bean的后续处理,并且抛出一个 org.springframework.beans.factory.BeanCreationException异常。

总结:
1. InitializingBean和init-method可以一起使用,Spring会先处理InitializingBean再处理init-method。init-method是通过反射执行的,而afterPropertiesSet是直接执行的,所以 afterPropertiesSet的执行效率比init-method要高,不过init-method消除了bean对Spring依赖,推荐使用init-method。
2. 如果一个bean被定义为非单例的,那么afterPropertiesSet和init-method在bean的每一个实例被创建时都会执行。单例bean的afterPropertiesSet和init-method只在bean第一次被实例时调用一次。一般情况下afterPropertiesSet和init-method都应用在单例的bean上。
3. @PostConstruct和@PreDestory可以通过在类方法上注解方式实现类似的功能。

猜你喜欢

转载自www.cnblogs.com/zqyanywn/p/9019911.html