SpringBoot: рефакторинг нового компонента, параметр 0 конструктора требовал один компонент, но были найдены 2JAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 SpringBoot: рефакторинг нового компонента, параметр 0 конструктора требовал один компонент, но были найдены 2

Сообщение Anonymous »

Я написал этот простой проект Spring Boot:

Код: Выделить всё

package com.example;

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

String addFoo(String foo);

}

Код: Выделить всё

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

}

Код: Выделить всё

package com.example;

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

Foo foo();

}

Код: Выделить всё

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

}

Код: Выделить всё

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

}

Код: Выделить всё

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. This layer should not be removed.
return new MyThingImpl(importantConfiguration); //using "new" keyword here!
}

}

Код: Выделить всё

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

}
И это работает прекрасно. Он выполняет бизнес-логику.
Я могу настроить свой компонент с помощью конфигурации и на уровне контроллера, чтобы получить его и выполнить свою бизнес-логику.
Однако у меня возникают следующие проблемы. Мы используем несколько инструментов статического анализа, а также инструменты проверки кода AI, каждый из которых отличается от других компаний, всего их 6.
Все они получили одинаковые отзывы:
  • Использование ключевого слова new здесь является антишаблоном Spring Boot. Следует использовать IoC, DI.
  • Эта реализация имеет проблемы с памятью при использовании дизайна bean-компонентов Spring Boot.
Не поняв отзывов, я попытался выполнить рефакторинг, чтобы:

Код: Выделить всё

package com.example;

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

String addFoo(String foo);

}

Код: Выделить всё

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

}

Код: Выделить всё

package com.example;

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

Foo foo();

}

Код: Выделить всё

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

}

Код: Выделить всё

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

}

Код: Выделить всё

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

}

Код: Выделить всё

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

}
Хотя я думаю, что это больше похоже на весну (не уверен, если вы поможете подтвердить), я получаю:

Код: Выделить всё

***************************
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]
Вопрос: как правильно реорганизовать это в Spring, чтобы проект работал как первое решение?
P.S. Если возможно, было бы здорово выделить недостатки решения 1. Пока я просто слепо доверяю и слежу за анализаторами, мне трудно понять, в чем проблема

Подробнее здесь: https://stackoverflow.com/questions/798 ... ed-a-singl
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»