aop EnableSchedulerLock MethodProxyScheduledLockAdvisor extends AbstractPointcutAdvisor
AnnotationData findAnnotation(Object target, Method method) { AnnotationData annotation = findAnnotation(method); if (annotation != null) { return annotation; } else { // Try to find annotation on proxied class Class<?> targetClass = AopUtils.getTargetClass(target); if (targetClass != null) { try { Method methodOnTarget = targetClass .getMethod(method.getName(), method.getParameterTypes()); return findAnnotation(methodOnTarget); } catch (NoSuchMethodException e) { return null; } } else { return null; } } } private AnnotationData findAnnotation(Method method) { net.javacrumbs.shedlock.core.SchedulerLock annotation = AnnotatedElementUtils.getMergedAnnotation(method, net.javacrumbs.shedlock.core.SchedulerLock.class); if (annotation != null) { return new AnnotationData(annotation.name(), annotation.lockAtMostFor(), annotation.lockAtMostForString(), annotation.lockAtLeastFor(), annotation.lockAtLeastForString()); } SchedulerLock annotation2 = AnnotatedElementUtils.getMergedAnnotation(method, SchedulerLock.class); if (annotation2 != null) { return new AnnotationData(annotation2.name(), -1, annotation2.lockAtMostFor(), -1, annotation2.lockAtLeastFor()); } return null; }
import org.springframework.aop.support.AopUtils;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.scheduling.support.ScheduledMethodRunnable;
import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;
class SpringLockConfigurationExtractor implements LockConfigurationExtractor
-------------------------------------------------------------------
implementation "net.javacrumbs.shedlock:shedlock-spring:${shedlockVersion}"
implementation "net.javacrumbs.shedlock:shedlock-provider-mongo:${shedlockVersion}"
shedlockVersion=4.15.1
----------------------------------------------------------------------
/** * Copyright 2009-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.javacrumbs.shedlock.spring.aop; import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock; import net.javacrumbs.shedlock.support.annotation.NonNull; import org.springframework.context.annotation.AutoProxyRegistrar; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; import static net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock.InterceptMode; import static net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock.InterceptMode.PROXY_METHOD; import static net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock.InterceptMode.PROXY_SCHEDULER; public class SchedulerLockConfigurationSelector implements ImportSelector { @Override public String[] selectImports(@NonNull AnnotationMetadata metadata) { AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(EnableSchedulerLock.class.getName(), false)); InterceptMode mode = attributes.getEnum("interceptMode"); if (mode == PROXY_METHOD) { return new String[]{AutoProxyRegistrar.class.getName(), MethodProxyLockConfiguration.class.getName()}; } else if (mode == PROXY_SCHEDULER) { return new String[]{AutoProxyRegistrar.class.getName(), SchedulerProxyLockConfiguration.class.getName(), RegisterDefaultTaskSchedulerPostProcessor.class.getName()}; } else { throw new UnsupportedOperationException("Unknown mode " + mode); } } }
/** * Copyright 2009-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.javacrumbs.shedlock.spring.aop; import net.javacrumbs.shedlock.core.DefaultLockingTaskExecutor; import net.javacrumbs.shedlock.core.LockProvider; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Role; @Configuration @Role(BeanDefinition.ROLE_INFRASTRUCTURE) class MethodProxyLockConfiguration extends AbstractSchedulerLockConfiguration { @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) MethodProxyScheduledLockAdvisor proxyScheduledLockAopBeanPostProcessor(@Lazy LockProvider lockProvider) { return new MethodProxyScheduledLockAdvisor(new SpringLockConfigurationExtractor(defaultLockAtMostForDuration(), defaultLockAtLeastForDuration(), getResolver(), getDurationConverter()), new DefaultLockingTaskExecutor(lockProvider)); } }
/** * Copyright 2009-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.javacrumbs.shedlock.spring.aop; import net.javacrumbs.shedlock.core.LockConfiguration; import net.javacrumbs.shedlock.core.LockingTaskExecutor; import net.javacrumbs.shedlock.core.LockingTaskExecutor.TaskResult; import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; import net.javacrumbs.shedlock.support.annotation.NonNull; import org.aopalliance.aop.Advice; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.aop.Pointcut; import org.springframework.aop.support.AbstractPointcutAdvisor; import org.springframework.aop.support.ComposablePointcut; import org.springframework.aop.support.annotation.AnnotationMatchingPointcut; import java.lang.annotation.Annotation; import java.util.Optional; class MethodProxyScheduledLockAdvisor extends AbstractPointcutAdvisor { private final Pointcut pointcut = new ComposablePointcut(methodPointcutFor(net.javacrumbs.shedlock.core.SchedulerLock.class)) .union(methodPointcutFor(SchedulerLock.class)); private final Advice advice; MethodProxyScheduledLockAdvisor(SpringLockConfigurationExtractor lockConfigurationExtractor, LockingTaskExecutor lockingTaskExecutor) { this.advice = new LockingInterceptor(lockConfigurationExtractor, lockingTaskExecutor); } @NonNull private static AnnotationMatchingPointcut methodPointcutFor(Class<? extends Annotation> methodAnnotationType) { return new AnnotationMatchingPointcut( null, methodAnnotationType, true ); } /** * Get the Pointcut that drives this advisor. */ @NonNull @Override public Pointcut getPointcut() { return pointcut; } @NonNull @Override public Advice getAdvice() { return advice; } private static class LockingInterceptor implements MethodInterceptor { private final SpringLockConfigurationExtractor lockConfigurationExtractor; private final LockingTaskExecutor lockingTaskExecutor; LockingInterceptor(SpringLockConfigurationExtractor lockConfigurationExtractor, LockingTaskExecutor lockingTaskExecutor) { this.lockConfigurationExtractor = lockConfigurationExtractor; this.lockingTaskExecutor = lockingTaskExecutor; } @Override public Object invoke(MethodInvocation invocation) throws Throwable { Class<?> returnType = invocation.getMethod().getReturnType(); if (returnType.isPrimitive() && !void.class.equals(returnType)) { throw new LockingNotSupportedException("Can not lock method returning primitive value"); } LockConfiguration lockConfiguration = lockConfigurationExtractor.getLockConfiguration(invocation.getThis(), invocation.getMethod()).get(); TaskResult<Object> result = lockingTaskExecutor.executeWithLock(invocation::proceed, lockConfiguration); if (Optional.class.equals(returnType)) { return toOptional(result); } else { return result.getResult(); } } private static Object toOptional(TaskResult<Object> result) { if (result.wasExecuted()) { return result.getResult(); } else { return Optional.empty(); } } } }