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

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");
}
}

Related

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

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

Spring boot - How to create spring beans for the objects created in static methods

I am trying to move old project to spring boot project. I created the spring project project and moved the code and now I am trying to springify the project by creating beans for the objects.
#SpringBootApplication
public class TestApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
#Override
public void run(String... args) throws CmdLineException {
final CommandLineArgs arguments = new CommandLineArgs();
CmdLineParser parser = new CmdLineParser(arguments);
parser.parseArgument(args);
A.generatedData(arguments);
}
}
class A{
public static void generatedData(CommandLineArgs arguments) {
LOG.info("Starting visualization.");
B b = new B(createModel(arguments));
b.build();
}
private static Model createModel(CommandLineArgs arguments) {
...
}
}
class B{
public void build() {
...
}
}
Some objects are created within the static method so I am not sure how to create beans of those objects. Can you please help convert this code in the spring world?
Original answer:
You typically just make a config class containing beans that return the object you want to wire in anywhere:
#Configuration
public class MyConfiguration {
#Bean
public B b() {
return new B();
}
}
And then you can wire them in like this:
#Component
#RequiredArgsConstructor
public class MyRunner implements CommandLineRunner {
private final B b;
#Override
public void run(String... args) throws Exception {
b.build();
}
}
Also, by implementing the CommandLineRunner or ApplicationRunner interfaces on a component, you can leave your application class alone...
These will run after the context is loaded and before your application starts.
You can also create beans with the #Component annotation:
#Component
public class B {
// ...
}
Or even create beans depending on other beans.
Here's a slightly more complex example:
#Configuration
public class DependentBeanConfig {
#Bean
SimpleBean someBean() { // interface
return new SomeBeanImpl(); // implementation
}
#Bean
DependentBean dependentBean(){
return new DependentBeanImpl(simpleBean());
}
}
#Configuration and #Service are just sub-types of the #Component annotation that basically do exactly the same. You can even create static beans inside them...
All of Spring is built upon this concept.
But you do not autowire static members, because that would be rather contradictory. If it belongs to the class it should not be wired in or vice versa. If you want to wire it in, it probably does not belong.
Another problem you might run in to is non-object oriented programming, where you might want to rethink the objects in the code.
Addendum:
To configure the bean create some setters:
public class B {
private YourProperty yourProperty;
//...
public setYourProperty(YourProperty yourProperty) {
this.yourProperty = yourProperty;
}
}
And in the bean creation:
#Configuration
public class MyConfiguration {
#Bean
public B b() {
B b = new B();
b.setYourProperty(yourProperty)
return b;
}
}
You can also wire in an Environment bean. Then you can fetch properties from the environment:
#Configuration
// You don't need this annotation for application.properties in Spring Boot projects
// I added it to easily understand what is going on
#PropertySource("classpath:yourpropertiesfile.properties")
public class MyConfiguration {
private Environment environment;
// ...
#Bean
public B b() {
B b = new B();
b.setYourProperty(environment.getProperty("yourProperty"))
return b;
}
}
You can then override these properties with commandline arguments as explained here.
The commandline / applciation runner I showed earlier can also take the application arguments without overriding environment variables.

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
}

Spring AOP - method aspect is not invoked

Sorry: Google Traductor (english basic)
Interface implemented by aspect:
public interface MinReader {
void interceptThoughts();
}
MinReader class that implements the interface, which contains the "Aspect"
#Aspect
public class Magician implements MinReader {
#Pointcut("within(paquetea.paqueteb.*)")
public void thinking() {
}
#Override
#Before("thinking()")
public void interceptThoughts() {
// Codigo
}
}
This is a part of my JavaConfig:
#Configuration
#EnableAspectJAutoProxy
public class SpringIdolConfig {
#Bean
public MinReader magician() {
return new Magician();
}
// Otros bean
}
the problem is that the "interceptThoughts" method is never invoked.
My "solution" is to change the return type of method "magician" in my JavaConfig:
"MinReader" -> "Magician"
#Bean
public Magician magician() {
return new Magician();
}
Why is that?
Is there any way to use "MinReader" instead of "Magician"?
UPDATE: these are the other beans:
package paquetea.paqueteb;
public interface Thinker {
void thinkOfSomething(String thoughts);
}
package paquetea.paqueteb;
public class Volunteer implements Thinker {
#Override
public void thinkOfSomething(String thoughts) {
//code
}
}
This is my full javaconfig:
#Configuration
#EnableAspectJAutoProxy
public class SpringIdolConfig {
#Bean
public MinReader magician() {
return new Magician();
}
#Bean
public Thinker volunteer() {
return new Volunteer();
}
}
I'm guessing a bit, but I think one of your problems is that you've got the pointcut expression wrong. If I've read the examples in here right, you should use:
#Pointcut("within(paquetea.paqueteb..*)")
Note the ..*, and not the .* that you had. I find that when I get pointcuts wrong, they can be very difficult to debug, as their normal way of failing is to just silently not attach to anything. (My preferred technique is to attach to methods annotated with a custom annotation; that makes it easy to control what's happening and easy to debug.)

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