Is there a way to annotate an entire class with #NewSpan? - Spring Boot/Sleuth - spring

Is there a way to annotate just the class and have all the methods in the class create new spans? Basically, I am trying to get sleuth/spring to create new spans for all calls in a given repository class.
spring-boot version: '2.7.0'
Something like -
import org.springframework.cloud.sleuth.annotation.NewSpan;
#Newspan
public class ContactOperations{
public void doSomething(){
}
public void doSomethingElse(){
}
.....
}
Instead of
public class ContactOperations{
#Newspan
public void doSomething(){
}
#Newspan
public void doSomethingElse(){
}
.....
}

No this is not possible. The annotation NewSpan is only allowed on methods as you can see in the source code:
#Retention(value=RUNTIME)
#Inherited
#Target(value=METHOD)
public #interface NewSpan

Related

Is there a way to #Import configuration and override the behavior of one of the bean?

I'm trying to create #Configuration class which will be #Import in different run time (in my project).
The configuration will create instance and I want for every run time to let him to do something else (like abstract behavior).
For example:
#Configuration
public class ConfigurationClass {
#Bean
public SomeInstace getInstance {
doSomething();
return new SomeInstance()
}
public abstract void doSomething();
}
//run time configuration class
#Import({ConfigurationClass.class})
#Configuration
public class RunTimeConfiguration{
#Override
public void doSomething(){
System.out.println("Do somthething else");
}
}

Can a class that is a Spring Bean also implement Runnable

For the first time, I am writing an app that manually creates a new thread. I am creating and using the thread like so:
#Service
public class MyAppService
{
myThread = new Thread(runnableThreadImpl);
myThread.start();
}
runnableThreadImpl is an instance of:
public class RunnableThreadImpl implements Runnable
{
public void run()
{
myProcessor.start()
}
}
myProcessor is an instance of:
#Component
#Transactional
public class MyProcessor
{
...
}
My boss would like me to combine RunnableThreadImpl and MyProcessor into one class that would look something like:
#Component
#Transactional
public class MyProcessor implements Runnable
{
public void run()
{
...
}
}
My question is: Are there any problems with having a Spring Bean implement Runnable?
Thx!

Spring-Boot Access object created in main from RequestMapping

I am using spring-boot for implementing a REST server. Inside a function for request mapping, I have to create an object which is heavyweight, so for every REST call I have do it and it is slowing things down. Is it possible to create the object in main and access from the function?
#SpringBootApplication
public class MyClass{
public static void main(String[] args) {
/* I want to initialize the object here */
SpringApplication.run(MyClass.class, args);
}
}
#RestController
public class MyController {
#RequestMapping("/go/to/user/summary")
public Users[] getUsers(#RequestParam(value="length", defaultValue="10") int length) {
/* I want to use the object here */
}
You can create a bean in MyClass and then consume that bean in MyController. Spring will only create a single instance of the bean so you'll avoid the cost of creating it multiple times. Something like this:
#SpringBootApplication
public class MyClass {
public static void main(String[] args) {
SpringApplication.run(MyClass.class, args);
}
#Bean
public Heavyweight heavyweight() {
// Initialize and return heavyweight object here
}
}
#RestController
public class MyController {
private final Heavyweight heavyweight;
#Autowired
public MyController(Heavyweight heavyweight) {
this.heavyweight = heavyweight;
}
#RequestMapping("/go/to/user/summary")
public Users[] getUsers(#RequestParam(value="length", defaultValue="10") int length) {
// Use heavyweight here
this.heavyweight.foo();
// ...
return users;
}
}
I think You can use #Service for this approach. Service class is Singleton so if You create object inside it on startup application then You can use it requests in Your controllers class.
Example service:
#Service
public class MyService{
private MyLargeObject largeObject;
public MyLargeObject set(MyLargeObject largeObject){
this.largeObject = largeObject;
}
public MyLargeObject get(){
return largeObject;
}
}
Example controller:
#RestController
public class MyController{
#Inject
private MyService myService;
#RequestMapping("/go/to/user/summary")
public Users[] getUsers(#RequestParam(value="length", defaultValue="10") int length) {
MyLargeObject o = myService.get();
}
}
EDIT1:
If You want init Your largeObject directly in service You can use #PostConstruct annotation. For example:
#PostConstruct
public void init() {
// initialization Your object here
}

Autowiring in implementation classes of an interface in Spring

I'm having a Spring boot application in which based on a variable, I need to call corresponding implementation classes of an interface. This is what I have right now:
public interface Parent{
public void call();
}
public class ABC implements Parent{
public void call(){
System.out.println("Called ABC");
}
}
public class XYZ implements Parent{
public void call(){
System.out.println("Called XYZ");
}
}
#Service("caller")
public class Caller{
#Autowired
protected OrderInfoRepository orderInfoRepository;
AnnotationConfigApplicationContext context;
public Caller(){
context = new AnnotationConfigApplicationContext(Config.class);
}
public void callMethod(String param){
Parent p = (Parent) context.getBean(param+"_Caller");
p.call();
}
}
#Configuration
public class Config{
#Bean(name="ABC_Caller")
public Parent getABC(){
return new ABC();
}
#Bean(name="XYZ_Caller")
public Parent getXYZ(){
return new XYZ();
}
}
#Repository
public interface MyRepo extends Repository<MyDAO, Long> {
// ....
}
Basically what I want to do is, based on the param passed to Caller.callMethod(), I want to add "_Caller" to the param, and call the corresponding implementation class. So, I'm defining a #Configuration class, where I define which implementation class to return. And then using the AnnotationConfigApplicationContext, I get the corresponding bean. This works fine.
The problem I'm having is, when I try to Autowire anything in the implementation classes, I get a NoSuchBeanDefinitionException. For instance, when I autowire in the implementation class ABC
public class ABC implements Parent{
#Autowired
MyRepo myRepo;
public void call(){
System.out.println("Called ABC");
}
}
I get Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.persistence.repositories.MyRepo] when I try to start the application. However, when I do the Autowiring in the Caller class instead, it works fine. I had asked a similar question a while back, but was not able to resolve it. Any ideas?

Spring AOP - advise super class method not overridden in subclass

public abstract class AService<T> {
public T needsToBeAdvised(T param) {
T result = doSomething(param);
return result;
}
}
#Service
public class BService extends AService<B> {
#Override
public T needsToBeAdvised(T param) {
return super.needsToBeAdvised(param);
}
}
#Service
public class CService extends AService<C> {}
// (B & C implement an interface AType)
#Component
#Aspect
public class MyAspect {
#Pointcut("execution(* package.AService+.needsToBeAdvised(*))")
private void aNeedToBeAdvised() {}
#AfterReturning(pointcut="aNeedToBeAdvised()", returning="param")
public void interceptNeedsToBeAdvised(JoinPoint joinPoint, AType param) {
// some action
}
}
Given this setup:
bService.needsToBeAdvised(bParam) //is intercepted
but,
cService.needsToBeAdvised(cParam) //is NOT.
How do I achieve this without overriding needsToBeAdvised() in CService?
EDIT:
I should add that BService and CService are both in the same package.
If I change my point-cut to the following:
#Pointcut("execution(* package.CService.needsToBeAdvised(*))")
cService.needsToBeAdvised(cParam) //is still not intercepted
The only way it works is if I override needsTobeAdvised() in CService
Are all services in the same package? Given from your example code, I suspect AService and BService to be in the package package, but CService to be in another package. If services indeed are in different packages, you have some options:
Move so that they are in the same package
Change you pointcut to be more generic, e.g. "execution(* *.A+.needsToBeAdvised(*))
Add more pointcuts

Resources