SpringBoot: Neues Refactoring für Bean, Parameter 0 des Konstruktors erforderte ein einzelnes Bean, es wurden jedoch 2 gJava

Java-Forum
Anonymous
 SpringBoot: Neues Refactoring für Bean, Parameter 0 des Konstruktors erforderte ein einzelnes Bean, es wurden jedoch 2 g

Post by Anonymous »

Ich habe dieses einfache Spring Boot-Projekt geschrieben:

Code: Select all

package com.example;

//just a simple interface, nothing spring-related here
public interface Foo {

String addFoo(String foo);

}

Code: Select all

package com.example;

//just a simple implementation, nothing spring-related here
public class FooImpl implements Foo {

@Override
public String addFoo(String foo) {
return "this is a foo WITHOUT dependency injection: " + foo;
}

}

Code: Select all

package com.example;

// just a simple interface, nothing spring-related here
public interface MyThing {

Foo foo();

}

Code: Select all

package com.example;

//just a simple implementation, nothing spring-related here
public class MyThingImpl implements MyThing {

private final FooImpl fooImpl;

public MyThingImpl(String importantConfiguration) {
System.out.println("this layer needs to get the @Configuration value to perform its logic: " + importantConfiguration);
fooImpl = new FooImpl(); //using "new" keyword here!
}

@Override
public Foo foo() {
return fooImpl;
}

}

Code: Select all

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

public static void main(final String[] args) {
SpringApplication.run(MyApplication.class);
}

}

Code: Select all

package com.example;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfiguration {

@Value("${my.important.configuration}")
private String importantConfiguration;

@Bean
public MyThing myThing() {
// need to configure MyThingImpl bean with importantConfiguration from this layer
return new MyThingImpl(importantConfiguration); //using "new" keyword here!
}

}

Code: Select all

package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;

@RestController
public class TestingSolutionOne {

private final MyThing myThing;

@Autowired
public TestingSolutionOne(MyThing myThingParam) {
// here, we inject the !configurable! MyThing bean via constructor injection
this.myThing = myThingParam;
}

@GetMapping(value = "/test")
public Optional mockFindById() {
String firstResult = myThing.foo().addFoo("testFoo");
System.out.println("First Result: " + firstResult);
return Optional.of(firstResult + "-");
}

}
Und das funktioniert einwandfrei. Es führt die Geschäftslogik aus.
Ich kann mein Bean mit der Konfiguration und auf der Controller-Ebene konfigurieren, um es abzurufen und meine Geschäftslogik auszuführen.
Ich erhalte jedoch die folgenden Probleme. Wir verwenden mehrere statische Analysetools sowie KI-Codeüberprüfungstools, jedes von anderen Unternehmen als das andere, insgesamt sechs davon.
Alle kamen mit dem gleichen folgenden Feedback:
  • Die Verwendung des Schlüsselworts new hier ist ein Anti-Pattern von Spring Boot. IoC, DI sollten genutzt werden.
  • Diese Implementierung hat Speicherprobleme bei der Verwendung des Spring Boot-Bean-Designs.
Da ich das Feedback nicht verstanden habe, habe ich versucht, eine Umgestaltung vorzunehmen:

Code: Select all

package com.example;

//just a simple interface, nothing spring-related here
public interface Foo {

String addFoo(String foo);

}

Code: Select all

package com.example;

import org.springframework.stereotype.Component;

@Component
// Now, I am marking this class as a Spring component
public class FooImpl implements Foo {

@Override
public String addFoo(String foo) {
return "this is a foo WITH dependency injection: " + foo;
}

}

Code: Select all

package com.example;

// just a simple interface, nothing spring-related here
public interface MyThing {

Foo foo();

}

Code: Select all

package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
// Now, I am marking this class as a Spring component, and FooImpl bean should be injected, no "new" keyword needed
public class MyThingImpl implements MyThing {

@Value("${my.important.configuration:default}")
private String importantConfiguration;

private final FooImpl fooImpl;

@Autowired
public MyThingImpl(FooImpl foo) {
System.out.println("I am not able to get the configuration from the @Configuration layer anymore, since I cannot 'new MyThingImpl(configuration)'' " + importantConfiguration);
fooImpl = foo;
}

@Override
public Foo foo() {
return fooImpl;
}

}

Code: Select all

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

public static void main(final String[] args) {
SpringApplication.run(MyApplication.class);
}

}

Code: Select all

package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfiguration {

//Think I am doing it wrong here, the configuration cannot be passed to MyThingImpl

private final MyThing myThing;

@Autowired
public MyConfiguration(MyThingImpl myThingParam) {
this.myThing = myThingParam;
}

@Bean
public MyThing myThing() {
return this.myThing;
}

}

Code: Select all

package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;

@RestController
public class TestingSolutionTwo {

private final MyThing myThing;

@Autowired
public TestingSolutionTwo(MyThing myThingParam) {
this.myThing = myThingParam;
}

@GetMapping(value = "/test")
public Optional mockFindById() {
String firstResult = myThing.foo().addFoo("testFoo");
System.out.println("First Result: "  + firstResult);
return Optional.of(firstResult + "-");
}

}
Obwohl ich denke, dass dies eher „frühlingsmäßig“ ist (ich bin mir nicht sicher, ob Sie mir das bestätigen könnten), erhalte ich Folgendes:

Code: Select all

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.example.TestingSolutionTwo required a single bean, but 2 were found:
- myThingImpl: defined in file [/Users/question/target/classes/com/example/MyThingImpl.class]
- myThing: defined by method 'myThing' in class path resource [com/example/MyConfiguration.class]
Frage: Wie kann man das richtig in Spring umgestalten, damit das Projekt wie Lösung eins funktioniert?
P.S. Wenn möglich, wäre es toll, die Nachteile von Lösung 1 hervorzuheben. Obwohl ich den Analysatoren blind vertraue und ihnen folge, fällt es mir schwer, das Problem zu verstehen

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post