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(); }}
- Spring对象生命周期控制
- 视图控制对象的生命周期
- iOS视图控制对象生命周期
- iOS视图控制对象生命周期
- iOS视图控制对象生命周期
- iOS视图控制对象生命周期
- iOS视图控制对象生命周期
- spring容器对象的生命周期
- IOS视图控制对象的生命周期
- iOS 视图控制对象的生命周期
- iOS视图控制对象生命周期及其作用
- iOS视图控制对象生命周期的区别
- 视图控制对象生命周期-init、viewD…
- 【Spring一】IOC控制对象
- spring容器创建对象的生命周期
- Spring IOC -bean对象的生命周期详解
- Spring IOC -bean对象的生命周期详解
- Spring-bean对象的生命周期详解
- Cooja 中自定义 Java Mote 使用 Collect-View
- 使用POTEUS软件来进行模拟仿真 8086汇编语言花式跑马灯课程设计及代码
- jquery 全选、反选、即点即改
- redis3.0.7源码阅读(一)源码文件
- Good Bye 2016D. New Year and Fireworks(dfs)
- Spring对象生命周期控制
- Mybatis入门例子(本文章转载自博主AndyChenzy,如需转载注明转载博主)
- 生物演示攻击
- 对CloseHandle用法的理解
- jdk1.8更新
- 在有GI软件的环境中,对单机db进行升级时遇到的问题
- rocketmq原理:name server ,broker, producer, consumer之间通信
- 设计模式——工厂模式
- redis3.0.7源码阅读(二)源码文件归类