1. 程式人生 > >spring中afterPropertiesSet方法與init-method配置描述

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

daemon sset end msg redis his === all HR

---恢復內容開始---

今天看了前輩們寫的代碼用到了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可以通過在類方法上註解方式實現類似的功能。

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