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();
}
}