Spring对象生命周期控制

1.Spring中常用对象

Spring框架中最常用对象有两个:BeanFactory和Bean。

1.1 BeanFactory

BeanFactory作用是:保存所有bean名字、类型等和beanDefinition的映射关系,以及保存实力化后单例bean名字、类型等和bean对象的映射关系。其中MVC框架中有两个beanFactory:一个是保存业务对象@Service @Commpont等注解产生的bean 。 另外一个BeanFactory是保存Controller相关的对象,其大部分是由@Controller注解产生的,以及一些Aop对象、interceptors等。
配置如下:父类BeanFactory
这里写图片描述
子类Controller相关的BeanFacotory:
这里写图片描述
Anyway这个不是这篇文章介绍的重点。

1.2 Bean

Bean是应用程序中的承接者,其内部包括大部分业务相关的业务逻辑。这个就不再进行详述。

2.Spring对象生命周期

初始化顺序:BeanFactory> Bean

2.1 Bean对象的生命周期控制

这里写图片描述

2.2 控制没有依赖关系Bean的初始化完成顺序

两个Bean实现SmartLifecycle接口,根据phase的大小,从小到大的顺序初始化完成Bean. 其他实现了Lifecycle的bean的phase值为0.

2.3 资源的预初始化

Bean实现SmartLifecycle接口,保证isAutoStartup()返回结果为true,在start()方法中实现预初始化的方法。
举个以前在POIOP控制MQ发送到指定机器Listener的实现

public class MtPoiopMqConsumer extends MtmqConsumer {

    private static final Logger LOGGER = LoggerFactory.getLogger(MtPoiopMqConsumer.class);

    @PostConstruct
    private void setAutoStartup(){

        String queueName = this.getQueue();
        boolean isMQServer = ServerUtil.isStartupListen(queueName);
        super.setAutoStartup(isMQServer);
        LOGGER.info("["+this.getMessageListener().getClass().getSimpleName()+"][isMQServer="+isMQServer+"]");
    }

    public void setAutoStartup(boolean autoStartup) {
        this.autoStartup = autoStartup;
    }

    @Override
    public boolean isAutoStartup() {
        return this.autoStartup;
    }
}

public class MtmqConsumer extends AbstractSmartLifecycle implements ConfigListener, Consumer {
                  ........
public void start() {
    super.start();

    List<BrokerBean> brokerList = null;

    if (!StringUtils.hasText(queue)) {
        Assert.hasText(topic, "topic 不允许为空");
        this.queue = NameRemoteService.getQueueNameByTopic(topic, nameService);
        Assert.hasText(queue, "queue 不允许为空,无法根据topic查询到对应的queue,topic name :" + topic);
    }

    //支持多个topic路由到一个queue,这样的话会有多个topic,暂时不处理变更事件
    //支持queue解决一个appkey订阅一个topic多遍,消费多遍
    brokerList = nameService.getReciveBrokersByQueue(queue);


    //NameService 和 ConfigMonitor都必须统一采用单例模式,简化初始化的复杂度
    ConfigMonitor.init(nameService).addReciveConfigListeners(this);

    if (CollectionUtils.isEmpty(brokerList)) {
        throw new IllegalArgumentException("no available mq broker address for topic: " + topic);
    }

    for (BrokerBean broker : brokerList) {
        ConnectionFactory connectionFactory = nameService.getConnectionFactory(broker);
        MtMessageListenerContainer listenerContainer = createListenerContainer(connectionFactory);
        doStartlistenerContainer(listenerContainer);
        listenerContainerMap.put(broker.getConnAddresses(), listenerContainer);
    }
}

可以看到Mq的listener相关的注册过程是在此处,如果你配置autoStartup=false,那么这个机器上配置的listener就不会和队列建立channer.
MtMessageListenerContainer listenerContainer = createListenerContainer(connectionFactory);
doStartlistenerContainer(listenerContainer);
listenerContainerMap.put(broker.getConnAddresses(), listenerContainer);

3.其他整体控制Bean初始化的方式

3.1 BeanFactoryPostProcessor使用场景

BeanFactoryPostProcessor主要是用于更改BeanFactory中BeanDefinition的属性字段或者属性值,以及向BeanFactory中注入新的beanName和BeanDefinition的关系。
示例1:资源占位符
PropertyPlaceholderConfigurer继承于BeanFactoryPostProcessor
这里写图片描述

//配置:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath*:database.properties</value>
            <value>classpath*:hosts.properties</value>
            <value>classpath*:es.proerties</value>
        </list>
    </property>
</bean>
//代码:
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
   try {
      Properties mergedProps = mergeProperties();

      // Convert the merged properties, if necessary.
      convertProperties(mergedProps);

      // Let the subclass process the properties.
      processProperties(beanFactory, mergedProps);
   }
   catch (IOException ex) {
      throw new BeanInitializationException("Could not load properties", ex);
   }
}
//可以看到props.setProperty(propertyName, convertedValue);来设置成配置文件中的值
protected void convertProperties(Properties props) {
   Enumeration<?> propertyNames = props.propertyNames();
   while (propertyNames.hasMoreElements()) {
      String propertyName = (String) propertyNames.nextElement();
      String propertyValue = props.getProperty(propertyName);
      String convertedValue = convertProperty(propertyName, propertyValue);
      if (!ObjectUtils.nullSafeEquals(propertyValue, convertedValue)) {
         props.setProperty(propertyName, convertedValue);
      }
   }
}

示例2:ConfigurationClassPostProcessor实现无配置文件

public class UserService {
    public void addUser() {
        System.out.println("add user");
    }
}
public class RoleService {
    public void addRole() {
        System.out.println("add role");
    }
}
@Configuration
public class ServiceConfig {

    @Bean(name = "roleService")
    public RoleService getRoleService() {
        return new RoleService();
    }

    @Bean(name = "userService")
    public UserService getUserService() {
        return new UserService();
    }
}
@Configuration
@Import(ServiceConfig.class)
public class AppConfig2 {

}

public class App {

    public static void main(String argss[]) {
        @SuppressWarnings("resource")
        ApplicationContext context = new AnnotationConfigApplicationContext(
                AppConfig2.class);
        RoleService roleService = (RoleService) context.getBean("roleService");
        roleService.addRole();

        UserService userService = (UserService) context.getBean("userService");
        userService.addUser();
    }

}
//等同于

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="roleService" class="com.lyx.RoleService"></bean>
    <bean id="userService" class="com.lyx.UserService"></bean>
</beans>


public class App2 {
    public static void main(String args[]) {
        @SuppressWarnings("resource")
        ApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        RoleService roleService = (RoleService) context.getBean("roleService");
        roleService.addRole();
        UserService userService = (UserService) context.getBean("userService");
        userService.addUser();

    }
}


#向BeanFactory中注入BeanDefinition的片段
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
      PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {

   /**
    * Derive further bean definitions from the configuration classes in the registry.
    */
   @Override
   public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
      RootBeanDefinition iabpp = new RootBeanDefinition(ImportAwareBeanPostProcessor.class);
      iabpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
      registry.registerBeanDefinition(IMPORT_AWARE_PROCESSOR_BEAN_NAME, iabpp);

      RootBeanDefinition ecbpp = new RootBeanDefinition(EnhancedConfigurationBeanPostProcessor.class);
      ecbpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
      registry.registerBeanDefinition(ENHANCED_CONFIGURATION_PROCESSOR_BEAN_NAME, ecbpp);

      int registryId = System.identityHashCode(registry);
      if (this.registriesPostProcessed.contains(registryId)) {
         throw new IllegalStateException(
               "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
      }
      if (this.factoriesPostProcessed.contains(registryId)) {
         throw new IllegalStateException(
               "postProcessBeanFactory already called on this post-processor against " + registry);
      }
      this.registriesPostProcessed.add(registryId);

      processConfigBeanDefinitions(registry);
   }

}

3.2 BeanPostProcessor使用场景

BeanPostProcessor主要功能是拦截所有bean的初始化的过程,对某类对象进行处理
我常遇到一些情形需要分不同的情况处理关系的时候,常使用manager来管理type和handler的映射关系,使用时传入type,获取handler然后调用handler的方法
CreateRelationHandler createRelationHandler = handleMap.get(type);

@Component
public class CreateRelationManager {
    private static final Logger LOGGER = LoggerFactory.getLogger(CreateRelationManger.class);
    private static final Map<CreateRelationVersion, CreateRelationHandler> handleMap = new HashMap<>();

    @Resource
    private List<CreateRelationHandler> createRelationHandlerList;

    @PostConstruct
    public void initHandleMap() {
        for (CreateRelationHandler createRelationHandler : createRelationHandlerList) {
            handleMap.put(createRelationHandler.getCreateRelationVersion(), createRelationHandler);
        }
    }
}

另外一种实现方式

@Component
public class CreateRelationManager {
    private static final Map<CreateRelationVersion, CreateRelationHandler> handleMap = new HashMap<>();

    public void register(CreateRelationHandler handler) {
        handleMap.put(handler.name(), handler);
    }

    public CreateRelationHandler getHandler(CreateRelationVersion version){
        return handleMap.get(version);
    }
}

@Component
public class CreateRelationHandlerBeanPostProcess implements BeanPostProcessor {

    @Autowired
    private CreateRelationManager createRelationManager;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof CreateRelationHandler) {
            createRelationManager.register(bean);
        }
        return bean;
    }
}

例如:品牌和品牌关系的创建、修改、是否可以采用这种方式,写一个controller,传入不同的名字,来判断应该使用哪个具体的bean来处理数据的新建、删除、修改等操作

3.3 ApplicationEvent事件使用场景

主要适用于观察者的情形,发布者:只发布事件,不关心发生这些事件需要哪些处理。 观察者:观察是否有某类自己关心的事件发生,如果发生自己进行一些处理,其不关系谁来发布事件,事件发布的逻辑。
一般是发布者和生产者不是一对一的情形
如分类情形:一个类别需要被两个不同的handler处理,以及可能后续还会增加,就适合使用ApplicationEvent和ApplicationListener,以及发布者实现ApplicationContextAware

public class BrandEvent extends ApplicationEvent {
    /**
     * Create a new ApplicationEvent.
     *
     * @param source the component that published the event (never {@code null})
     */
    private Object context;

    public BrandEvent(Object source, Object context) {
        super(source);
        this.context=context;
    }

    public Object getContext() {
        return context;
    }

    public void setContext(Object context) {
        this.context = context;
    }
}

@Component
public class BrandChangePublisher implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }

    public void publishBrandInsert(){
        BrandEvent brandEvent=new BrandEvent(applicationContext,"insert");
        applicationContext.publishEvent(brandEvent);
    }

    public void publishBrandUpdate(){
        BrandEvent brandEvent=new BrandEvent(applicationContext,"update");
        applicationContext.publishEvent(brandEvent);
    }
}


@Component
public class BrandInsertListener1 implements ApplicationListener<BrandEvent> {
    @Override
    public void onApplicationEvent(BrandEvent event) {
        String operate=(String)event.getContext();
        if(event.getContext() != null && event.getContext().equals("insert"))
            System.out.println("InsertListener1 operate="+operate);
    }
}
@Component
public class BrandInsertListener2 implements ApplicationListener<BrandEvent> {
    @Override
    public void onApplicationEvent(BrandEvent event) {
        String operate=(String)event.getContext();
        if(event.getContext() != null && event.getContext().equals("insert"))
            System.out.println("InsertListener2 operate="+operate);
    }
}

@Component
public class BrandUpdateListener implements ApplicationListener<BrandEvent> {
    @Override
    public void onApplicationEvent(BrandEvent event) {
        String operate=(String)event.getContext();
        if(event.getContext() != null && event.getContext().equals("update"))
            System.out.println("UpdateListener operate="+operate);
    }
}

public class ApplicationEventTest extends BaseTest {
    @Resource
    private BrandChangePublisher brandChangePublisher;

    @Test
    public void testPublisher(){
        brandChangePublisher.publishBrandInsert();
        brandChangePublisher.publishBrandUpdate();
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值