Scoped Methods Spring Boot Starter
Usage
Maven
<dependency>
<groupId>io.github.kshashov</groupId>
<artifactId>scoped-methods-spring-boot-starter</artifactId>
<version>0.9.2</version>
</dependency>
Gradle
implementation group: 'io.github.kshashov', name: 'scoped-methods-spring-boot-starter', version: '0.9.2'
Firstly, you need to enable scoped methods support by adding @EnableScopedMethods
annotation to your configuration
@EnableScopedMethods(proxyTargetClass = true)
@SpringBootApplication
public class MethodScopesApplication {
public static void main(String[] args) {
SpringApplication.run(MethodScopesApplication.class, args);
}
}
After that you can annotate your methods with @ScopedMethod
annotation and get the current scope id in runtime with ScopedMethodsHolder
singleton:
@Service
public class Service1 {
@ScopedMethod(key = "inner")
public void doSomething() {
log.info(ScopedMethodsHolder.getCurrent());
}
}
@Service
public class Service2 {
@ScopedMethod(key = "outer")
public void doSomething() {
log.info(ScopedMethodsHolder.getCurrent()); // outer
service1.doSomething(); // inner
log.info(ScopedMethodsHolder.getCurrent()); // outer
}
}
On practice
Imagine that you need to add some kind of metadata for a method so that it acts differently depending on this metadata. For example, you need to use replica or master datasources in your backend methods. Using this library you just need to specify replica scope for some methods:
public interface MyService {
@ScopedMethod("replica")
String get(String name);
}
Then, somewhere in the AbstractRoutingDataSource
implementation, you could have something like this:
public class MasterSlaveDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
String scopeId = ScopedMethodsHolder.getCurrent();
return scopeId != null? scopeId : "master"; // Use master DS by default
}
}
@EnableScopedMethods
Arguments:
mode
: indicates how interceptor should be applied.- The default is
AdviceMode#PROXY
. Limitations:- Allows for the interception of calls through the proxy only. Local calls within the same class cannot get intercepted that way
AdviceMode#ASPECTJ
. Limitations:- no support for overriden method
- no support for meta-annotations
- The default is
proxyTargetClass
: indicate whether subclass-based (CGLIB) proxies are to be created as opposed to standard Java interface-based proxies. Applicable only ifmode
is set toAdviceMode#PROXY
order
: indicates the ordering of the execution of the interceptor when multiple advices are applied at a specific joinpoint
@ScopedMethod
Arguments:
value
orkey
: scope identifiergroup
: allow you to have several sets of scopes for different purposes@ScopedMethod(group = "datasource", key = "master") @ScopedMethod(group = "datasource", key = "replica") @ScopedMethod(group = "mygroup", key = "key1") @ScopedMethod(group = "mygroup", key = "key2")
You can repeat this annotation for a single method to enable several scopes.
ScopedMethodsHolder
Inject ScopedMethodsHolder
bean to get the current scope id or check the presence of the specific scope. Do not forget to specify the group
argument if you have declare your scopes with this parameter.
ScopedMethodsHolder.getCurrent(); // default "" group
ScopedMethodsHolder.getCurrent("datasource");
ScopedMethodsHolder.getCurrent("mygroup");
ScopedMethodsHolder.contains("myscope"); // default "" group
ScopedMethodsHolder.contains("mygroup", "myscope");
ScopedMethodsConfiguration
You can declare ScopedMethodsConfiguration
implementations for each scope group to subscribe on scope changing. For example, it may be useful to keep track of a case when a master scope is created inside a replica scope.