package com.sogou.bizdev.compass.core.datasource.config; import java.util.Collections; import java.util.List; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.core.Conventions; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import com.sogou.bizdev.compass.core.datasource.MasterSlaveDataSource; import com.sogou.bizdev.compass.core.datasource.ShardDataSource; import com.sogou.bizdev.compass.core.datasource.SingleDataSource; import com.sogou.bizdev.compass.core.datasource.availability.DatabaseAvailabilityDetector; import com.sogou.bizdev.compass.core.datasource.config.enums.DataSourceType; import com.sogou.bizdev.compass.core.datasource.config.enums.LoadBalanceStrategyType; import com.sogou.bizdev.compass.core.selector.loadbalance.WeightedRandom; import com.sogou.bizdev.compass.core.selector.loadbalance.WeightedRoundRobin; /** * 读取datasource XML配置,构建ShardDataSource和MasterSlaveDataSource * @author gly * @since 1.0.0 */ public class DatasourceBeanDefinitionParser extends AbstractBeanDefinitionParser implements DataSourceTag { /** * 解析datasource节点,翻译为封装数据源类型 * @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext) */ @Override protected AbstractBeanDefinition parseInternal(Element dataSourceElement,ParserContext parserContext) { List<Element> groupElements = DomUtils.getChildElementsByTagName(dataSourceElement, GROUP); if (CollectionUtils.isEmpty(groupElements)) { throw new IllegalArgumentException(GROUP+" ChildElements is null!"); } DataSourceType dataSourceType = getDataSourceType(dataSourceElement,groupElements); switch(dataSourceType) { case SHARD_DATASOURCE: return parseShardDataSource(dataSourceElement, groupElements, parserContext); case MASTER_SLAVE_DATASOURCE: return parseMasterSlaveDataSource(dataSourceElement, groupElements.get(0), parserContext); default: throw new IllegalArgumentException("Unsupport data source type from the configuration."); } } private String getShardDataSourceId(Element dataSourceElement) { String shardDataSourceId=dataSourceElement.getAttribute(ID); if(!StringUtils.hasText(shardDataSourceId)) { throw new IllegalArgumentException("Property '"+ID+"' of element '"+DATASOURCE+"' must be set."); } return shardDataSourceId.trim(); } /** * 分库数据源解析(主从库分表/分库不分表/分库分表) * @param dataSourceElement 主节点 * @param masterSlaveElements 数据源组节点 * @param parserContext * @return */ private AbstractBeanDefinition parseShardDataSource(Element dataSourceElement,List<Element> masterSlaveElements, ParserContext parserContext) { String shardDataSourceId=this.getShardDataSourceId(dataSourceElement); BeanDefinitionBuilder shardDataSourceBeanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(ShardDataSource.class); shardDataSourceBeanDefinitionBuilder.addPropertyValue(ID, shardDataSourceId); List<AbstractBeanDefinition> masterSlaveDataSourceBeanDefinitions = this.createMasterSlaveBeanDefinitions( dataSourceElement, shardDataSourceId, masterSlaveElements, parserContext); shardDataSourceBeanDefinitionBuilder.addPropertyValue(ShardDataSource.MASTER_SLAVE_DATA_SOURCES_PROPERTY_NAME, masterSlaveDataSourceBeanDefinitions); //数据库SQL解析器,默认解析器不替换 Element sqlInterceptorElement = DomUtils.getChildElementByTagName(dataSourceElement, SQLINTERCEPTOR); //允许用户不设置sqlInterceptor,默认为DefaultSqlInterceptor if(sqlInterceptorElement!=null) { this.parseSqlInterceptor(sqlInterceptorElement, shardDataSourceBeanDefinitionBuilder, parserContext); } //数据库路由选择器,不能为空 Element routerElement = DomUtils.getChildElementByTagName(dataSourceElement, ROUTER); if(routerElement == null) { throw new IllegalArgumentException("if ShardDataSource,Property '"+ROUTER+"' of element '"+DATASOURCE+"' must be set!"); } this.parseRouteStrategy(routerElement, shardDataSourceBeanDefinitionBuilder, parserContext); return shardDataSourceBeanDefinitionBuilder.getBeanDefinition(); } private void parseSqlInterceptor(Element sqlInterceptorElement,BeanDefinitionBuilder shardDataSourceBeanDefinitionBuilder,ParserContext parserContext) { BeanDefinitionContext beanDefinitionContext=getBeanDefinitionContext(sqlInterceptorElement,CLASS,REF,true); String sqlInterceptorValue=beanDefinitionContext.getAttributeValue(); if (beanDefinitionContext.isRef()) { shardDataSourceBeanDefinitionBuilder.addPropertyReference(ShardDataSource.SQL_INTERCEPTOR_PROPERTY_NAME,sqlInterceptorValue); } else { AbstractBeanDefinition sqlInterceptorBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(sqlInterceptorValue).getBeanDefinition(); //可能在此处会进行property的注入 shardDataSourceBeanDefinitionBuilder.addPropertyValue(ShardDataSource.SQL_INTERCEPTOR_PROPERTY_NAME, parsePropertyElement(sqlInterceptorElement, sqlInterceptorBeanDefinition, parserContext)); } } private void parseRouteStrategy(Element routerElement,BeanDefinitionBuilder shardDataSourceBeanDefinitionBuilder,ParserContext parserContext) { BeanDefinitionContext beanDefinitionContext=getBeanDefinitionContext(routerElement, CLASS, REF,true); String shardDataSourceRouteStrategyValue=beanDefinitionContext.getAttributeValue(); //分库情况下必须设置路由选择器 if (beanDefinitionContext.isRef()) { shardDataSourceBeanDefinitionBuilder.addPropertyReference(ShardDataSource.SHARD_DATA_SOURCE_ROUTE_STRATEGY_PROPERTY_NAME, shardDataSourceRouteStrategyValue); } else { BeanDefinition shardDataSourceRouteStrategyBeanDefinition= BeanDefinitionBuilder.rootBeanDefinition(shardDataSourceRouteStrategyValue).getBeanDefinition(); //可能在此处会进行property的注入 shardDataSourceBeanDefinitionBuilder.addPropertyValue( ShardDataSource.SHARD_DATA_SOURCE_ROUTE_STRATEGY_PROPERTY_NAME, parsePropertyElement(routerElement,shardDataSourceRouteStrategyBeanDefinition,parserContext)); } } /** * 主从库数据源解析 * @param dataSourceElement * @param masterSlaveElement * @param parserContext * @return */ private AbstractBeanDefinition parseMasterSlaveDataSource(Element dataSourceElement, Element masterSlaveElement, ParserContext parserContext) { String shardDataSourceId=this.getShardDataSourceId(dataSourceElement); List<AbstractBeanDefinition> beanDefinitions= this.createMasterSlaveBeanDefinitions(dataSourceElement, shardDataSourceId, Collections.singletonList(masterSlaveElement), parserContext); return beanDefinitions.get(0); } /** * 主从库数据源解析 * @param dataSourceElement * @param masterSlaveElement * @param parserContext * @return */ private List<AbstractBeanDefinition> createMasterSlaveBeanDefinitions(Element dataSourceElement, String shardDataSourceId,List<Element> masterSlaveElements, ParserContext parserContext) { //1.心跳探测器availabilityDetector Element availabilityDetectorElement = DomUtils.getChildElementByTagName(dataSourceElement, AVAILABILITYDETECTOR); //2.数据库负载均衡策略loadBalanceStrategy Element loadBalanceElement = DomUtils.getChildElementByTagName(dataSourceElement, LOADBALANCE); //3.pingStatement Element pingStatementElement=DomUtils.getChildElementByTagName(dataSourceElement,PINGSTATEMENT); //dataSourcePrototypeAttributeValue可以为空 String dataSourcePrototypeAttributeValue = dataSourceElement.getAttribute(DATASOURCE_PROTOTYPE); List<AbstractBeanDefinition> masterSlaveDataSourceBeanDefinitions = new ManagedList<AbstractBeanDefinition>(); for (Element masterSlaveElement : masterSlaveElements) { AbstractBeanDefinition masterSlaveBeanDefinition = doCreateMasterSlaveDataSourceBeanDefinition( shardDataSourceId, masterSlaveElement, parserContext, dataSourcePrototypeAttributeValue, availabilityDetectorElement, loadBalanceElement, pingStatementElement); masterSlaveDataSourceBeanDefinitions.add(masterSlaveBeanDefinition); } return masterSlaveDataSourceBeanDefinitions; } /** * 解析主从库xml定义,构建主从库datasource * @param shardDataSourceId 数据源id * @param masterSlaveElement 数据源组节点 * @param parserContext * @param dataSourcePrototypeAttributeValue 数据源原型 * @param availabilityDetectorElement 心跳探测器节点 * @param loadBalanceElement 负载均衡器节点 * @return */ private AbstractBeanDefinition doCreateMasterSlaveDataSourceBeanDefinition( String shardDataSourceId, Element masterSlaveElement, ParserContext parserContext, String dataSourcePrototypeAttributeValue, Element availabilityDetectorElement, Element loadBalanceElement, Element pingStatementElement) { String masterSlaveDataSourceId = masterSlaveElement.getAttribute(NAME); if(!StringUtils.hasText(masterSlaveDataSourceId)) { throw new IllegalArgumentException("shardDataSourceId:["+shardDataSourceId+"],attribute '"+NAME+"' of element '"+GROUP+"' must be set!"); } masterSlaveDataSourceId=masterSlaveDataSourceId.trim(); BeanDefinitionBuilder masterSlaveDataSourceBeanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(MasterSlaveDataSource.class); masterSlaveDataSourceBeanDefinitionBuilder.addPropertyValue(ID, masterSlaveDataSourceId); masterSlaveDataSourceBeanDefinitionBuilder.addPropertyValue(MasterSlaveDataSource.SHARD_DATA_SOURCE_ID_PROPERTY_NAME, shardDataSourceId); //master必须设置 Element masterElement = DomUtils.getChildElementByTagName(masterSlaveElement, MASTER); if(masterElement==null) { throw new IllegalArgumentException("shardDataSourceId:["+shardDataSourceId+"],Property '"+MASTER+"' of element '"+GROUP+"' must be set."); } this.parseMasterDataSource( masterElement, masterSlaveDataSourceBeanDefinitionBuilder, parserContext, masterSlaveDataSourceId, dataSourcePrototypeAttributeValue); //slave可以为空 List<Element> slaveElements = DomUtils.getChildElementsByTagName(masterSlaveElement, SLAVE); if(!CollectionUtils.isEmpty(slaveElements)) { this.parseSlaveDataSources( slaveElements, masterSlaveDataSourceBeanDefinitionBuilder, parserContext, masterSlaveDataSourceId, dataSourcePrototypeAttributeValue); } //pingStatementElement可以为空 if(pingStatementElement!=null) { String pingStatement=pingStatementElement.getAttribute(PINGSTATEMENT_VALUE); if(StringUtils.hasText(pingStatement)) { masterSlaveDataSourceBeanDefinitionBuilder.addPropertyValue(MasterSlaveDataSource.PING_STATEMENT_PROPERTY_NAME, pingStatement.trim()); } } //心跳探测器availabilityDetector可以为空,为空的时候不进行检测 if(availabilityDetectorElement != null) { this.parseAvailabilityDetector(availabilityDetectorElement, masterSlaveDataSourceBeanDefinitionBuilder, parserContext); } //数据库负载均衡策略loadBalanceStrategy可以为空,为空的时候默认为WeightedRandom if(loadBalanceElement!=null) { this.parseLoadBalance(loadBalanceElement, masterSlaveDataSourceBeanDefinitionBuilder, parserContext); } return masterSlaveDataSourceBeanDefinitionBuilder.getBeanDefinition(); } private void parseAvailabilityDetector(Element availabilityDetectorElement,BeanDefinitionBuilder masterSlaveDataSourceBeanDefinitionBuilder,ParserContext parserContext) { //ref和class可以都为空,为空的时候为DatabaseAvailabilityDetector BeanDefinitionContext availabilityDetectorBeanDefinitionContext= getBeanDefinitionContext(availabilityDetectorElement, CLASS, REF,false); String availabilityDetectorValue=availabilityDetectorBeanDefinitionContext.getAttributeValue(); if (availabilityDetectorBeanDefinitionContext.isRef()) { masterSlaveDataSourceBeanDefinitionBuilder.addPropertyReference(MasterSlaveDataSource.AVAILABILITY_DETECTOR_PROPERTY_NAME, availabilityDetectorValue); } else { AbstractBeanDefinition availabilityDetectorBeanDefinition=createAvailabilityDetectorBeanDefinition(availabilityDetectorElement,availabilityDetectorValue); masterSlaveDataSourceBeanDefinitionBuilder.addPropertyValue(MasterSlaveDataSource.AVAILABILITY_DETECTOR_PROPERTY_NAME, parsePropertyElement(availabilityDetectorElement,availabilityDetectorBeanDefinition,parserContext)); } } private void parseLoadBalance(Element loadBalanceElement,BeanDefinitionBuilder masterSlaveDataSourceBeanDefinitionBuilder,ParserContext parserContext) { BeanDefinitionContext loadBalanceBeanDefinitionContext=this.getLoadBalanceBeanDefinitionContext(loadBalanceElement); String loadBalanceValue=loadBalanceBeanDefinitionContext.getAttributeValue(); if(loadBalanceBeanDefinitionContext.isRef()) { masterSlaveDataSourceBeanDefinitionBuilder.addPropertyReference(MasterSlaveDataSource.LOAD_BALANCE_PROPERTY_NAME, loadBalanceValue); } else { AbstractBeanDefinition loadBalanceBeanDefinition=BeanDefinitionBuilder.rootBeanDefinition(loadBalanceValue).getBeanDefinition(); masterSlaveDataSourceBeanDefinitionBuilder.addPropertyValue(MasterSlaveDataSource.LOAD_BALANCE_PROPERTY_NAME, parsePropertyElement(loadBalanceElement,loadBalanceBeanDefinition,parserContext)); } } private void parseMasterDataSource( Element masterElement, BeanDefinitionBuilder masterSlaveDataSourceBeanDefinitionBuilder, ParserContext parserContext, String masterSlaveDataSourceId, String dataSourcePrototypeAttributeValue) { BeanDefinitionBuilder masterBeanDefinitionBuilder= BeanDefinitionBuilder.rootBeanDefinition(SingleDataSource.class); masterBeanDefinitionBuilder.addPropertyValue(ID, masterSlaveDataSourceId+".master"); masterBeanDefinitionBuilder.addPropertyValue(SingleDataSource.TARGET_DATA_SOURCE_PROPERTY_NAME, parseSingleTargetDatasourceBeanDefinition(masterElement,dataSourcePrototypeAttributeValue, parserContext)); AbstractBeanDefinition masterBeanDefinition=masterBeanDefinitionBuilder.getBeanDefinition(); masterSlaveDataSourceBeanDefinitionBuilder.addPropertyValue(MasterSlaveDataSource.MASTER_DATA_SOURCE_PROPERTY_NAME, masterBeanDefinition); } private AbstractBeanDefinition createSlaveBeanDefinition( int index, Element slaveElement, String masterSlaveDataSourceId, String dataSourcePrototypeAttributeValue, ParserContext parserContext) { BeanDefinitionBuilder slaveBeanDefinitionBuilder= BeanDefinitionBuilder.rootBeanDefinition(SingleDataSource.class); slaveBeanDefinitionBuilder.addPropertyValue(ID, masterSlaveDataSourceId+".slave"+index); slaveBeanDefinitionBuilder.addPropertyValue(SingleDataSource.TARGET_DATA_SOURCE_PROPERTY_NAME, parseSingleTargetDatasourceBeanDefinition(slaveElement,dataSourcePrototypeAttributeValue, parserContext)); String strWeight = slaveElement.getAttribute(WEIGHT); if(StringUtils.hasText(strWeight)) { strWeight=strWeight.trim(); int weight=SingleDataSource.DEFAULT_WEIGHT; try { weight=Integer.parseInt(strWeight); } catch(Throwable ex) { throw new IllegalArgumentException("masterSlaveDataSourceId:["+masterSlaveDataSourceId+"],slave :["+index+"] '"+WEIGHT+"':["+strWeight+"] must be int!"); } slaveBeanDefinitionBuilder.addPropertyValue(SingleDataSource.WEIGHT_PROPERTY_NAME,Integer.valueOf(weight)); } return slaveBeanDefinitionBuilder.getBeanDefinition(); } private void parseSlaveDataSources( List<Element> slaveElements, BeanDefinitionBuilder masterSlaveDataSourceBeanDefinitionBuilder, ParserContext parserContext, String masterSlaveDataSourceId, String dataSourcePrototypeAttributeValue) { ManagedList<AbstractBeanDefinition> slaveBeanDefinitions = new ManagedList<AbstractBeanDefinition>(slaveElements.size()); int index=0; for (Element slaveElement : slaveElements) { index++; AbstractBeanDefinition slaveBeanDefinition=this.createSlaveBeanDefinition( index, slaveElement, masterSlaveDataSourceId, dataSourcePrototypeAttributeValue, parserContext); slaveBeanDefinitions.add(slaveBeanDefinition); } masterSlaveDataSourceBeanDefinitionBuilder.addPropertyValue(MasterSlaveDataSource.SLAVE_DATA_SOURCES_PROPERTY_NAME, slaveBeanDefinitions); } /** * 解析心跳探测器 * @param availabilityDetectorElement * @return */ private AbstractBeanDefinition createAvailabilityDetectorBeanDefinition(Element availabilityDetectorElement,String availabilityDetectorClassName) { BeanDefinitionBuilder availabilityDetectorBeanDefinitionBuilder = getAvailabilityDetectorBeanDefinitionBuilder(availabilityDetectorClassName); String enableDetector= availabilityDetectorElement.getAttribute(ENABLED); String interval= availabilityDetectorElement.getAttribute(INTERVAL); String detectPoolSize= availabilityDetectorElement.getAttribute(DETECTPOOLSIZE); if(StringUtils.hasText(enableDetector)) { availabilityDetectorBeanDefinitionBuilder.addPropertyValue(DatabaseAvailabilityDetector.ENABLED_PROPERTY_NAME, enableDetector.trim().toLowerCase().equals("true"));//是否开启心跳探测 } if(StringUtils.hasText(interval)) { try { availabilityDetectorBeanDefinitionBuilder.addPropertyValue(DatabaseAvailabilityDetector.INTERVAL_PROPERTY_NAME, Integer.valueOf(interval.trim()));//心跳探测间隔 } catch (Exception e) { throw new IllegalArgumentException("property '"+INTERVAL+"' of '"+AVAILABILITYDETECTOR+"' is not Number format "); } } if(StringUtils.hasText(detectPoolSize)) { try { availabilityDetectorBeanDefinitionBuilder.addPropertyValue(DatabaseAvailabilityDetector.DETECT_POOL_SIZE_PROPERTY_NAME, Integer.valueOf(detectPoolSize.trim()));//心跳探测线程数 } catch (Exception e) { throw new IllegalArgumentException("property '"+DETECTPOOLSIZE+"' of '"+AVAILABILITYDETECTOR+"' is not Number format "); } } return availabilityDetectorBeanDefinitionBuilder.getBeanDefinition(); } private BeanDefinitionContext getLoadBalanceBeanDefinitionContext(Element loadBalanceElement) { String loadBalanceStrategyType =loadBalanceElement.getAttribute(LOADBALANCESTRATEGY); if(StringUtils.hasText(loadBalanceStrategyType)) { Class<?> loadBalanceClass=getLoadBalanceClassByType(loadBalanceStrategyType.trim()); return new BeanDefinitionContext(false,loadBalanceClass.getName()); } return getBeanDefinitionContext(loadBalanceElement,CLASS, REF,true); } /** * 查询对应的负载均衡策略 * @param loadBalanceStrategyType * @return */ private Class<?> getLoadBalanceClassByType(String loadBalanceStrategyType) { switch (LoadBalanceStrategyType.parse(loadBalanceStrategyType)) { case WEIGHTED_RANDOM: return WeightedRandom.class; case WEIGHTED_ROUND_ROBIN: return WeightedRoundRobin.class; default: throw new IllegalArgumentException("Property '"+LOADBALANCESTRATEGY+"' of element '"+LOADBALANCE+"',value:["+loadBalanceStrategyType+ "] can't find LoadBalance Class."); } } /** * 根据className和classRefName获取该节点的Class定义以及是否为引用注入 * @param element * @param classAttributeName * @param refAttributeName * @return */ private BeanDefinitionContext getBeanDefinitionContext(Element element, String classAttributeName,String refAttributeName,boolean disallowBothNull) { BeanDefinitionContext beanDefinitionContext=new BeanDefinitionContext(); if(element == null) { return beanDefinitionContext; } String classValue = element.getAttribute(classAttributeName); if (!StringUtils.hasText(classValue)) { classValue = null; } else { classValue = classValue.trim(); } String refValue = element.getAttribute(refAttributeName); if (!StringUtils.hasText(refValue)) { refValue = null; } else { refValue = refValue.trim(); } if (classValue!=null && refValue!=null) { throw new IllegalArgumentException("Property '"+classAttributeName+"' and '"+refAttributeName+"' of element '"+element.getTagName()+"' can not set both!"); } if(classValue==null && refValue==null) { if(disallowBothNull) { throw new IllegalArgumentException("Property '"+classAttributeName+"' and '"+refAttributeName+"' of element '"+element.getTagName()+"' can not be both null!"); } beanDefinitionContext.setAttributeValue(null); beanDefinitionContext.setRef(false); } else if(classValue==null && refValue!=null) { beanDefinitionContext.setAttributeValue(refValue); beanDefinitionContext.setRef(true); } else { beanDefinitionContext.setAttributeValue(classValue); beanDefinitionContext.setRef(false); } return beanDefinitionContext; } /** * 根据availabilityDetectorClass获取数据库连接池监控实现,默认DatabaseAvailabilityDetector * @param availabilityDetectorClassName * @return */ private BeanDefinitionBuilder getAvailabilityDetectorBeanDefinitionBuilder(String availabilityDetectorClassName) { if (!StringUtils.hasText(availabilityDetectorClassName)) { return BeanDefinitionBuilder.rootBeanDefinition(DatabaseAvailabilityDetector.class); } //MUST an instance of AvailabilityDetector return BeanDefinitionBuilder.rootBeanDefinition(availabilityDetectorClassName); } /** * 继承prototype基类的属性配置 * @param targetDataSourceElement * @param dataSourcePrototypeAttributeValue * @param parserContext * @return */ private AbstractBeanDefinition parseSingleTargetDatasourceBeanDefinition( Element targetDataSourceElement, String dataSourcePrototypeAttributeValue, ParserContext parserContext) { BeanDefinitionBuilder targetDataSourceBeanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(); if(StringUtils.hasText(dataSourcePrototypeAttributeValue)) { targetDataSourceBeanDefinitionBuilder.setParentName(dataSourcePrototypeAttributeValue.trim()); } AbstractBeanDefinition targetDataSourceBeanDefinition = targetDataSourceBeanDefinitionBuilder.getBeanDefinition(); List<Element> propertyElements = DomUtils.getChildElementsByTagName(targetDataSourceElement, PROPERTY); NamedNodeMap attributes=targetDataSourceElement.getAttributes(); if (!CollectionUtils.isEmpty(propertyElements)) { for (Element propertyElement : propertyElements) { parserContext.getDelegate().parsePropertyElement(propertyElement, targetDataSourceBeanDefinition); } } if (attributes!=null && attributes.getLength() > 0) { for (int i=0;i<attributes.getLength();i++) { Node node=attributes.item(i); if (!(node instanceof Attr)) { continue; } Attr attr = (Attr) node; String attributeName = attr.getLocalName(); String attributeValue = attr.getValue(); MutablePropertyValues pvs = targetDataSourceBeanDefinition.getPropertyValues(); if (pvs.contains(attributeName)) { parserContext.getReaderContext().error("Property '" + attributeName + "' is already defined using " + "both <property> and inline syntax. Only one approach may be used per property.", attr); continue; } if (attributeName.endsWith(REF_SUFFIX)) { attributeName = attributeName.substring(0, attributeName.length() - REF_SUFFIX.length()); pvs.addPropertyValue(Conventions.attributeNameToPropertyName(attributeName), new RuntimeBeanReference(attributeValue)); } else { pvs.addPropertyValue(Conventions.attributeNameToPropertyName(attributeName), attributeValue); } } } return targetDataSourceBeanDefinition; } /** * 对设置的bean进行properties属性注入 * @param beanElement * @param beanDefinition * @param parserContext * @return */ private BeanDefinition parsePropertyElement(Element beanElement,BeanDefinition beanDefinition,ParserContext parserContext) { if(beanElement==null) { return beanDefinition; } List<Element> propertyElements = DomUtils.getChildElementsByTagName(beanElement, PROPERTY); if(CollectionUtils.isEmpty(propertyElements)) { return beanDefinition; } for (Element propertyElement:propertyElements) { parserContext.getDelegate().parsePropertyElement(propertyElement, beanDefinition); } return beanDefinition; } /** * 获取数据源类型(分库:含分库不分表/分库分表/主从库分表,主从库:主从库不分表) * @param groupElements * @return */ private DataSourceType getDataSourceType(Element dataSourceElement,List<Element> groupElements) { Assert.isTrue(!CollectionUtils.isEmpty(groupElements)); if (groupElements.size() > 1) { return DataSourceType.SHARD_DATASOURCE; } if(groupElements.size()==1) { Element dataSourceRouterElement = DomUtils.getChildElementByTagName(dataSourceElement,ROUTER); //主从库设置了router的也认为是分库,而且必须自定义实现 if(dataSourceRouterElement!=null) { return DataSourceType.SHARD_DATASOURCE; } else { return DataSourceType.MASTER_SLAVE_DATASOURCE; } } return DataSourceType.NONE; } }