zoukankan      html  css  js  c++  java
  • 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可以通过在类方法上注解方式实现类似的功能。

  • 相关阅读:
    Java:前程似锦的 NIO 2.0
    优秀的程序员都热爱写作
    Java -- JDBC 学习--获取数据库链接
    前端学习 -- Html&Css -- 条件Hack 和属性Hack
    前端学习 -- Html&Css -- ie6 png 背景问题
    前端学习 -- Html&Css -- 框架集
    ECMAScript 6 -- 字符串的扩展
    ECMAScript 6 -- 数组的解构赋值
    前端学习 -- Html&Css -- 表单
    前端学习 -- Html&Css -- 表格
  • 原文地址:https://www.cnblogs.com/zqyanywn/p/9019911.html
Copyright © 2011-2022 走看看