Is it bad to put #Service/#Component along with #Bean? - spring

Suppose I have this service bean:
#Service
public class MyService{
private final HashMap<String,String> values;
...
}
with the values being:
com.foo:
values:
a: world
b: helo
I may want to create it inside of a configuration:
#Configuration
#ConfigurationProperties(prefix="com.foo")
public class MyConf{
private Map<String, String> values;
#Bean
public MyService myService(){
return new MyService(values);
}
}
But I fear that spring could do something strange like creating 2 beans or dunno what...is this a good practice or should I just move #ConfigurationProperties inside of the #Service itself?

You can inject your configuration directly into your Service
#Service
public class MyService{
private final MyConf conf;
public MyService(MyConf conf) {
this.conf = conf;
}
}
And remove the #Bean annotation from MyConf allong with myservice method.

You should not do that, as it will create two beans of the same type.
In your case, you have not mentioned different names for the beans
so it will override if spring.main.allow-bean-definition-overriding=true else it will fail.
PS: For #Service annotation to create a bean, the class package should be configured in the #ComponentScan or in the base scan package

If you want to use your properties values in your Service class (or anywhere else) you should just inject it :
#Service
public class MyService{
#Autowired
private MyConf myConf;
}

Related

Autowiring of Service and Service Implementation class

Following are my code
#RestController
public class EmployeeController {
#Autowired
EmployeeService empService;
public EmployeeController (EmployeeService Impl empServiceImpl) {
super();
this.empService = empServiceImpl;
}
}
#Service
public interface EmployeeService {
public List<EmployeeDTO> getAllEmployeeDetails()
}
public class EmployeeServiceImpl {
public List<EmployeeDTO> getAllEmployeeDetails(){
//methods business logic and repo call goes here
}
}
When I start my server I am getting below error.
Parameter 1 of constructor in
com.app.in.controller.EmployeeController required a bean of type
'com.app.in.service.EmployeeServiceImpl' that could not be found
My understanding might be wrong. If I annotate the EmployeeSeriveImpl class also with #Service then it working.Is that is the correct way to do it ? My question is the service interface is annotated with #Service still why its implementation is also required to annotation. Please let me know if I miss something in that ? What is the standard method to solve this issue ?
You can get your dependency injected using a constructor. And #Autowired is optional in this case.
This is your example, but with a few corrections:
#RestController
public class EmployeeController {
// private final is a good practice. no need in #Autowire
private final EmployeeService empService;
// this constructor will be used to inject your dependency
// #Autowired is optional in this case, but you can put it here
public EmployeeController (EmployeeService empServiceImpl) {
this.empService = empServiceImpl;
}
}
I assume you have an interface EmployeeService and class EmployeeServiceImpl which implements that interface and is Spring Bean.
Something like this:
#Service
public class EmployeeServiceImpl implements EmployeeService {}
Why this #Service is needed? When you put this annotation on your class, Spring knows this is a bean that Spring should manage for you (container will create an instance of it and inject it wherever it is needed).
Check Spring docs to get more details about Dependency Injection.
The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null.

Service Implementation - how to choose which service implementation will be used based on application.properties attribute?

I have two service implementations:
Service interface:
/**
* Service used for resolving external ID for the entity.
*/
public interface ResolveService {
String valueToResolve(String id);
}
Implementation of Service - A:
#Service
public class ResolveServiceAImpl implements {
#Override
public String valueToResolve(String id) {
// grpc impl...
}
}
Implementation of Service - B:
#Service
public class ResolveServiceBImpl implements {
#Override
public String valueToResolve(String id) {
// jpa impl...
}
}
For now, this is resolved with #Qualifier and this implementation works:
#Qualifier("resolveServiceBImpl")
#Autowired
private ResolveService resolveService;
The problem for me is that I don't want to define in every class String value of #Qualifier. I would like to define #Qualifier value in one place, let's say in application.properties file.
application.properties:
resolve.service.active=resolveServiceBImpl
This implementation is not working:
#Value("'${resolve.service.active}')")
private String resolveServiceActive;
#Qualifier(resolveServiceActive)
#Autowired
private ResolveService resolveService;
The error I am getting is Attribute value must be constant. Cannot find bean with qualifier null.
Is there any other way how to resolve #Qualifier value, so that I need to assign it manually in every class separately?
#jonrsharpe tnx for answer.
I resolved it with a #Profile.
SOLUTION:
Service A Implementation:
#Service
#Profile("A")
public class ResolveServiceAImpl implements ResolveService {...
Service B Implementation:
#Service
#Profile("B")
public class ResolveServiceBImpl implements ResolveService {...
and application.properties:
spring.profiles.active=A
And for the test I used #ActiveProfiles("A").
This solved my problem.

How to declare multiple object with same class but using different properties in spring boot

I want declare multiple object using same class but different properties in Spring boot annotation
application.properties
test1.name=Ken
test2.name=Anthony
the code example
#Component
public class People {
private String name;
public String getName() {
return this.name;
}
}
#SpringBootApplication
public class Application {
#AutoWired
public People man1;
#AutoWired
public People man2;
System.out.println(man1.getName());
System.out.println(man2.getName());
}
I try to add #ConfigurationProperties(prefix="test1") before declare man1
but it returned
The annotation #ConfigurationProperties is disallowed for this location
#ConfigurationProperties is only allow to be placed on the #Bean method in the #Configuration class or at the class level. For the former case , it will map the properties from the application.properties to the bean instance , which means you have to :
#SpringBootApplication
public class Application {
#Bean
#ConfigurationProperties(prefix="test1")
public People man1() {
return new People();
}
#Bean
#ConfigurationProperties(prefix="test2")
public People man2() {
return new People();
}
}
And since both man1 and man2 are the same type , you have to further use #Qualifier to tell Spring which instance you actually want to inject by specifying its bean name. The bean name can be configured by #Bean("someBeanName"). If #Bean is used without configuring the bean name, the method name will be used as the bean name. (i.e. man1 and man2)
#Autowired
#Qualifier("man1")
public People man1;
#Autowired
#Qualifier("man2")
public People man2;

Spring bean management using #Autowired

I have a messaging call that will process my payload which starts from MyClass. In load test i see that the first payload is getting over written by the next. All my classes are spring managed by #Autowired. Obviously the bean scope is singleton and thats why this is happening. But i do not want to use new operator and want it to be spring annotation configured. Is there any way to fix this issue of losing data ?
UPDATE
My configuration looks like below :
Public class MyClass {
...
#Autowired
public MyService myService;
...
}
#Component
#Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class MyService{
#Autowired
public Aone one;
#Autowired
public Atwo two;
...
}
#Component
#Scope(value="prototype")
public class Aone {
}
I am attempting this configuration after suggestions from net. For every call i get in MyClass a new instance of MyService will be created and from there on all other instances like Aone / Atwo should have new instance, will this configuration be ok ?

How to configure Services with Spring Data JPA repositories with spring Java Configuration

I am trying to figure out how to get a hold of the OrderRepository so that I can pass it into the constructor of the OrderServiceImpl using Spring's java configuration (I already know how to do it with xml configuration).
#Configuration
#ComponentScan(basePackages = "com.sample.app")
#EnableJpaRepositories("com.sample.app")
#EnableTransactionManagement
public class AppConfig
{
#Bean
public OrderService orderService()
{
return new OrderServiceImpl(orderRepository());
}
#Bean
public OrderRepository orderRepository()
{
return ??? What goes here ???
}
...
}
#Configuration
#ComponentScan(basePackages = "com.sample.app")
#EnableJpaRepositories("com.sample.app")
#EnableTransactionManagement
public class AppConfig {
#Autowired
private OrderRepository orderRepository;
#Bean
public OrderService orderService() {
return new OrderServiceImpl(orderRepository);
}
}
Something like that should work. Or simply put a field inside your OrderServiceImpl which is annotated with #Autowired and remove the constructor which takes an orderRepository. Or rely on component-scanning and remove the #Bean methods all together.
You have a component-scan and #Bean method, you might run into duplicate instances of your service that way (if it is annotated with #Service).

Resources