Spring对象生命周期控制

来源:互联网 发布:h5 刮刮卡 源码 编辑:程序博客网 时间:2024/06/04 17:41

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>//代码:@Overridepublic 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");    }}@Configurationpublic 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);

@Componentpublic 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);        }    }}

另外一种实现方式

@Componentpublic 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);    }}@Componentpublic 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;    }}@Componentpublic 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);    }}@Componentpublic 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);    }}@Componentpublic 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);    }}@Componentpublic 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();    }}
0 0
原创粉丝点击