Scoped Methods

Scoped Methods Spring Boot Starter

License

License

Categories

Categories

Spring Boot Container Microservices
GroupId

GroupId

io.github.kshashov
ArtifactId

ArtifactId

scoped-methods-spring-boot-starter
Last Version

Last Version

0.9.2
Release Date

Release Date

Type

Type

jar
Description

Description

Scoped Methods
Scoped Methods Spring Boot Starter
Source Code Management

Source Code Management

https://github.com/kshashov/scoped-methods

Download scoped-methods-spring-boot-starter

How to add to project

<!-- https://jarcasting.com/artifacts/io.github.kshashov/scoped-methods-spring-boot-starter/ -->
<dependency>
    <groupId>io.github.kshashov</groupId>
    <artifactId>scoped-methods-spring-boot-starter</artifactId>
    <version>0.9.2</version>
</dependency>
// https://jarcasting.com/artifacts/io.github.kshashov/scoped-methods-spring-boot-starter/
implementation 'io.github.kshashov:scoped-methods-spring-boot-starter:0.9.2'
// https://jarcasting.com/artifacts/io.github.kshashov/scoped-methods-spring-boot-starter/
implementation ("io.github.kshashov:scoped-methods-spring-boot-starter:0.9.2")
'io.github.kshashov:scoped-methods-spring-boot-starter:jar:0.9.2'
<dependency org="io.github.kshashov" name="scoped-methods-spring-boot-starter" rev="0.9.2">
  <artifact name="scoped-methods-spring-boot-starter" type="jar" />
</dependency>
@Grapes(
@Grab(group='io.github.kshashov', module='scoped-methods-spring-boot-starter', version='0.9.2')
)
libraryDependencies += "io.github.kshashov" % "scoped-methods-spring-boot-starter" % "0.9.2"
[io.github.kshashov/scoped-methods-spring-boot-starter "0.9.2"]

Dependencies

compile (4)

Group / Artifact Type Version
org.springframework.boot : spring-boot-starter jar 2.4.4
javax.validation : validation-api jar 2.0.1.Final
org.springframework.boot : spring-boot-starter-aop jar 2.4.4
org.aspectj : aspectjrt jar 1.8.9

test (1)

Group / Artifact Type Version
org.springframework.boot : spring-boot-starter-test jar 2.4.4

Project Modules

There are no modules declared in this project.

Scoped Methods Spring Boot Starter

Maven metadata URL JitPack CircleCI codecov

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
  • proxyTargetClass: indicate whether subclass-based (CGLIB) proxies are to be created as opposed to standard Java interface-based proxies. Applicable only if mode is set to AdviceMode#PROXY
  • order: indicates the ordering of the execution of the interceptor when multiple advices are applied at a specific joinpoint

@ScopedMethod

Arguments:

  • value or key: scope identifier
  • group: 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.

Versions

Version
0.9.2
0.9.1