public class NameMatchTransactionAttributeSource
implements TransactionAttributeSource, EmbeddedValueResolverAware, InitializingBean, Serializable {
protected static final Log logger = LogFactory.getLog(NameMatchTransactionAttributeSource.class);
/** Keys are method names; values are TransactionAttributes. */
private final Map<String, TransactionAttribute> nameMap = new HashMap<>();
private StringValueResolver embeddedValueResolver;
public void setNameMap(Map<String, TransactionAttribute> nameMap) {
nameMap.forEach(this::addTransactionalMethod);
public void setProperties(Properties transactionAttributes) {
TransactionAttributeEditor tae = new TransactionAttributeEditor();
Enumeration<?> propNames = transactionAttributes.propertyNames();
while (propNames.hasMoreElements()) {
String methodName = (String) propNames.nextElement();
String value = transactionAttributes.getProperty(methodName);
TransactionAttribute attr = (TransactionAttribute) tae.getValue();
addTransactionalMethod(methodName, attr);
public void addTransactionalMethod(String methodName, TransactionAttribute attr) {
if (logger.isDebugEnabled()) {
logger.debug("Adding transactional method [" + methodName + "] with attribute [" + attr + "]");
if (this.embeddedValueResolver != null && attr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) attr).resolveAttributeStrings(this.embeddedValueResolver);
this.nameMap.put(methodName, attr);
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.embeddedValueResolver = resolver;
public void afterPropertiesSet() {
for (TransactionAttribute attr : this.nameMap.values()) {
if (attr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) attr).resolveAttributeStrings(this.embeddedValueResolver);
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (!ClassUtils.isUserLevelMethod(method)) {
// Look for direct name match.
String methodName = method.getName();
TransactionAttribute attr = this.nameMap.get(methodName);
// Look for most specific name match.
String bestNameMatch = null;
for (String mappedName : this.nameMap.keySet()) {
if (isMatch(methodName, mappedName) &&
(bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) {
attr = this.nameMap.get(mappedName);
bestNameMatch = mappedName;
protected boolean isMatch(String methodName, String mappedName) {
return PatternMatchUtils.simpleMatch(mappedName, methodName);