I have two Services and a Controller that I am trying to set up, like this:
Controller class:
#Controller
public class MyController {
#Autowired
IMyService1 service;
}
Service 2:
#Service
public class MyService2 implements IMyService2 { }
Service 1:
#Service
public class MyService1 implements IMyService1 {
#Autowired
IMyService2 myService2; // this bean is not getting created
}
Everything is set up correctly in beans.xml to pick up the Components in the component scan, and everything is under the same base package.
The first service is properly injected into the Controller class, but the second service is failing to be injected (BeanCreationException) into the first Service.
Has anyone run into this or any ideas/suggestions on what I may be doing wrong here?
I did some research on the subject, but I couldn't find an answer that solved this problem and I was only able instantiating the second service dynamically without #Service annotation.
Controller: Don't touch, it's the same
#Controller
public class MyController {
#Autowired
IMyService1 service;
}
Service 2: Remove #Service from the second service
public class MyService2 implements IMyService2 {
public void doSomething() {
// your code
}
}
Service 1: Remove #Autowired and dynamically instantiate your second service
#Service
public class MyService1 implements IMyService1 {
public void actionWithService2() {
new MyService2().doSomething();
}
}
Related
I have intermediate skills in Springboot and can develop simple to medium complex applications but this one is throwing me off a little bit.
I have a #Service that extends Guava's AbstractIdleService and a #Controller that has instance of the service autowired.
In the service, I have a method, say performTransaction() that is annotated with #Transactional (ofcourse to let Spring take care of transactions) and it does create a proxy of the service class. But when I debug the application I can see that the proxy that is injected in the controller contains all super class (AbstractIdleService) class fields as null meaning super() is not called when the proxy of my service was created. Because of this the application is failing to initialize when calling the super class's (AbstractIdleService) startAsync method. I am not really sure how to make this work.
I have added some code below for illustration.
This is my service class:
import com.google.common.util.concurrent.AbstractIdleService;
import org.springframework.transaction.annotation.Transactional;
#Service
public class MyService extends AbstractIdleService {
#Transactional
public void performTransaction() {
}
}
This is the controller that uses the above service:
#Controller
public void MyController {
private MyService service;
private EurekaRegistration eurekaRegistration;
#Autowired
public MyController(MyService service, EurekaRegistration eurekaRegistration) {
this.service = service; // This is where the proxy contains all AbstractIdleService fields null
this.eurekaRegistration = eurekaRegistration;
}
#EventListener({ ApplicationPreparedEvent.class })
public void handleApplicationPreparedEvent() {
this.service.startAsync(); // This line throws NPE, as delegate in the parent is null
this.service.awaitRunning();
}
}
I must use AbstractIdleService as that is the organizational convention and I need to invoke some startup code in the startAsync method. But invoking startAsync method on the service is causing a NullPointerException as it uses a parent field that is null because the proxy initialization never called super.
I'm not 100% sure if this is the actual problem, but try something like this (untested):
Interface for proxy:
import com.google.common.util.concurrent.Service;
public interface MyService extends Service {
void performTransaction();
}
Implementation:
import com.google.common.util.concurrent.AbstractIdleService;
import org.springframework.transaction.annotation.Transactional;
#Service
public class MyServiceImpl extends AbstractIdleService implements MyService {
#Transactional
public void performTransaction() {
}
}
Controller, declare service interface, not implementation:
#Controller
public void MyController {
private MyService service;
private EurekaRegistration eurekaRegistration;
#Autowired
public MyControlle(MyService service, EurekaRegistration eurekaRegistration) {
this.service = service;
this.eurekaRegistration = eurekaRegistration;
}
}
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.
I'm refactoring an existing application to use Spring Boot. The issues I've faced here are generally of the type "why is this not working anymore".
I have three packages
- nl.myproject.boot
- nl.myproject
- nl.myproject.rest
My current problem is that all #Services that I #Inject in a #RESTController resolve to null when a method is called on them.
The service and dao are part of the nl.myproject package and the reason it's not nl.myproject.core is a legacy issue.
A related issue is that my #Configuration components don't seem to be loaded through #ComponentScan and I have to import them manually. I also had to exclude Test configuration to prevent Test configs from being loaded, which also seemed weird.
Internal calls from the service layer during start up, such as data preparation works normally. Any such manager is also #Injected. This is just to say that any of the typical injection mistakes such as manual instantiation or injecting a class instead of an interface don't apply.
I'd also be grateful for debugging tips. My Java has gotten a little rusty.
#EnableAutoConfiguration
#ComponentScan(basePackages= {
"nl.myproject",
"nl.myproject.boot",
"nl.myproject.dao",
"nl.myproject.service",
"nl.myproject.webapp"},
excludeFilters= {
#ComponentScan.Filter(type=FilterType.REGEX,pattern={".*Test.*"}),
#ComponentScan.Filter(type=FilterType.REGEX,pattern={".*AppConfig"})
}
)
#Configuration
#EnableConfigurationProperties
#Import({
JPAConfig.class,
RestConfig.class,
BootConfig.class
})
public class Startup {
public static void main(String[] args) throws Exception {
SpringApplication.run(Startup.class, args);
}
}
#RestController
#RequestMapping(value="/json/tags")
public class JsonTagController extends JsonBaseController {
#Inject
TagManager tagMgr;
public interface TagManager extends BaseManager<Tag,Long> {
[...]
}
#Service("tagManager")
public class TagManagerImpl extends BaseManagerImpl<Tag, Long> implements
TagManager {
#Inject
TagDao dao;
[...]
#Inject is a annotation specified by JSR-330 (standard) whereas #Autowired is annotation specified by Spring.
They just do the same dependency injection. You can both of them in the same code.
Just the modification (separation of the concerns) you need :
public interface TagManager {
[...]
}
#Service
public class TagManagerImpl implements TagManager {
#Inject
private TagDao dao;
// inject that service rather than extending
#Inject
private BaseManager<Tag,Long> baseManager;
}
public interface BaseManager<Tag,Long> {
[...]
}
#Service
public class BaseManagerImpl<Tag,Long> implements BaseManager<Tag,Long> {
....
}
Just one thing you do for checking, just modify to basePackages= {"nl.myproject"} - just provide only base package, that's enough for spring to scan the components in every package.
Hope this may help :)
There is the spring-boot application that uses spring-aop. proxy-target-class is true.
I'm trying to create a test for a service class. This service depends on a component class. I want to inject a mock into the service instead of the real component.
I found some similar questions:
Mocking a property of a CGLIB proxied service not working
Injecting Mockito mocks into a Spring bean
I choose this answer to the last question, and I have tried to implement this approach. I chose it because it is not tied to the implementation details of the proxy classes and I can easily use a config class in other tests.
Below there is the example which simulates the real problem.
#org.aspectj.lang.annotation.Aspect
#org.springframework.stereotype.Component
public class Aspect {
#Before("within(demo.Service)")
public void someAdvice() {
System.out.println("advice");
}
}
#org.springframework.stereotype.Service
public class Service {
#Autowired
private Component component;
public void action() {
System.out.println(component.action());
}
}
#org.springframework.stereotype.Component
public class Component {
public String action() {
return "real action";
}
}
#SpringApplicationConfiguration
public class ServiceTest extends BaseTest {
#Autowired
Service service;
#Test
public void testAction() {
service.action();
}
#Configuration
public static class Config {
#Mock Component mock;
public Config() {
MockitoAnnotations.initMocks(this);
}
#Bean
public Component component() {
Mockito.when(mock.action()).thenReturn("mock action");
return mock;
}
}
}
Complete example: https://github.com/eds0404/spring-inject-mock-into-proxy
The above code is not working as I expect, the service does not use mock ("real action" will be printed if you run test). But the above code works fine if the Component class is not marked with #Component annotation, and its objects are created by the method with #Been annotation.
How to solve this issue? If this is wrong approach, what is best practice?
A question on how Spring injection works? If I inject same service in a class and all its sub-classes is it going to to inefficient? How does Spring's container going to store/control this?
public class baseClass {
#Autowired
private iService serviceName
}
public class extendedClassA extends baseClass {
#Autowired
private iService serviceName
}
public class extendedClassB extends extendedClassA {
#Autowired
private iService serviceName
}
Thanks..
I haven't tried but I believe it is going to cause problem.
The main problem is not due to Spring, but variable shadowing in your example. BaseClass' serviceName is shadowed by child class, that means, if you haven't done special handling, BaseClass' serviceName is going to be null.
You may want to consider doing this:
// !!!! Mind your naming convention!!!!!!
public class BaseClass {
#Autowired
private FooService fooService;
protected FooService getFooService() {
return this.fooService;
}
public setFooService(FooService fooService) { ... }
}
public class ExtendedClassA extends BaseClass {
// no need to inject fooService again, whenever it need to use that,
// simply do getFooService() and use it
}
Adrian Shum response seems fine but you need to declare too your BaseClass bean in your applicationContext file with the property "abstract=true"
<bean id="baseClass" class="BaseClass" abstract="true"/>