In an MVC application, where will the dependency injection take place? - java

When using Spring and Spring's MVC, where should the dependency injection (DI) take place?
Example, if you have a controller, and many actions in the controller.
Would you be doing:
#RequestMapping("/blah")
public String SomeAction()
{
ApplicationContext ctx = new AnnotationConfigApplicationContext();
MyService myService = ctx.getBean("myService");
// do something here
return "someView";
}
Would this be the best practice approach? Or is their a better way?

The whole idea of Dependency Injection is to not have your classes know or care of how they get the objects they depend on. With injection, these dependencies should just "appear" without any request (hence the Inversion of Control). When using ApplicationContext#getBean(String), you're still asking for the dependency (a la Service Locator) and this is not Inversion of Control (even if this allows you to change the implementation easily).
So, instead, you should make your MyController a Spring managed bean and inject MyService using either setter or constructor based injection.
public class MyController {
private MyService myService;
public MyController(MyService aService) { // constructor based injection
this.myService = aService;
}
public void setMyService(MySerice aService) { // setter based injection
this.myService = aService;
}
#Autowired
public void setMyService(MyService aService) { // autowired by Spring
this.myService = aService;
}
#RequestMapping("/blah")
public String someAction()
{
// do something here
myService.foo();
return "someView";
}
}
And configure Spring to wire things together.

Don't use getbean, that loses the purpose of doing DI. Use #Autowired instead. DI is meant to be used in a layered system like view, service, DAO, so that each layer is not depending on each other.

As a compliment to Pascal's post,
Martin Fowler: Inversion of Control Containers and the Dependency Injection pattern is a must read.
And as cometta stated, that you should use #Autowire annotation to achieve that. In addition to that, Spring supports name based and type based convention injections. I suggest you to read on that.

Related

Does Spring dependency injection really make the goal loose coupling?

Spring is famous with it Inverse Control and DI.
I know that dependency injection have several ways like Constructor Dependency Injection etc.
for example
we usually use #Autowired annotation to do Dependency Injection.
when we develop MVC web project.
My question is very simple
Why is a spring framework loosely coupled?
Suppose We have two Dao class One is Dao1 ,other is Dao2
Dao1
public class Dao {
public void sayhi() {
System.out.println("hello");
}
}
Dao2
public class Dao2 {
public void saygoodbye() {
System.out.println("say goodbye");
}
}
If we do not use Autowired annotation
the service should be
public class Service {
Dao1 dao=new Dao1();
Dao2 dao2=new Dao2();
public void sayhi() {
dao.sayhi();
}
public void saygoodbye() {
dao2.saygoodbye();
}
}
and the Controller should be
#RestController
public class Controller {
Service service=new Service( );
#GetMapping("test")
public void saysomething() {
service.saygoodbye();
service.sayhi();
}
}
If we do not use Autowired annotation , we must use new keyword to make instance
If we use Autowired annotation
the code
Dao1 dao=new Dao1();
Dao2 dao2=new Dao2();
just change it into
#Autowired
Dao1 dao
#Autowired
Dao2 dao2
So,without Autowired annotation
Why is a spring framework loosely coupled?
If you use new keyword, then Service need to know how Dao1 and Dao2 are implemented and instantiated(concrete type, parameters...), more knowledge means more coupling.
However, if you use #Autowired, then Spring do everything for you by Dependency Injection technique, the coupling becomes more loosely.
The advantage of loosely coupling is: your code becomes more testable and maintainable.
You should read about the many benefits of dependency injection, this is a good place to start: https://en.m.wikipedia.org/wiki/Dependency_injection.
But if you want a short one line answer its main benefit is that it makes the code easier to test.
If you create the DAO classes with the new keyword in your service class you cannot easily replace them with mock objects during testing of the service class.
First, note that field injection has been discouraged by Spring for several years now. Second, dependency injection alone does not magically guarantee loose coupling. Abstraction is also necessary. Since there is no abstraction in these examples, Service is coupled just as tightly to the Dao implementations whether you inject or instantiate them.
Spring still offers other benefits here, including lifecycle management and cohesion. Also note that since the Dao classes are not final, there is potential for abstraction, because Spring could inject subclasses whereas direct instantiation will always give you the base class.

Spring dependency injection #Autowired VS dependency injection of an object without #Autowired

what is the main difference between injecting objects with #Autowired and injecting without it ?
I know that spring will initialize the bean , but what it is really offering ?
There are several ways to configure Spring beans and inject dependencies using Spring. One way is by using constructor injection, where the constructor of your Spring bean has arguments which are the dependencies that should be injected:
#Component
public class MyBean {
private final SomeDependency something;
#Autowired
public MyBean(SomeDependency something) {
this.something = something;
}
}
However, since Spring 4.3, it is not necessary anymore to use #Autowired on such a constructor (click link for Spring documentation). So you can write it without the #Autowired:
#Component
public class MyBean {
private final SomeDependency something;
public MyBean(SomeDependency something) {
this.something = something;
}
}
This will work exactly the same as the code above - Spring will automatically understand that you want the dependency to be injected via the constructor. The fact that you can leave out #Autowired is just for convenience.
So, to answer your question: there is no difference.
#Autowired (so the injection) in some situation cannot be used, an example is if your autowired bean not ready because of some async stuff but in the target bean you want to use that.
So in this situation do not use inject (#Autowired) it is better to inject the ApplicationContext and in the exact moment get your bean from there by name or by class (there is a lot off possibilities there).
You can consider the #Autowired with the #Lazy annotation too.

how to initialize a bean in spring container once and use it everywhere

actually i'm using spring for developing a web application, the problem i'm facing is that i'm initializing a bean as soon as the spring container is getting loaded, now i have to use that bean in different parts of my program.
constraints that i have
1. i can get application context everywhere and get that bean but according to my problem i should get that bean without writing that redundant code again and again.so is there any way by which i can initialize that bean and use it directly everywhere in my program.
If you already initialized your bean you can get access to it via #Autowired from each Component in your Spring Application.
private SomeClass myBean;
#Autowired
public void setMyBean(SomeClass myBean){
this.myBean =myBean;
}
Or just:
#Autowired
private SomeClass myBean;
I prefer the first method, looks fancier in my eyes.
You should not get your bean from the context directly, instead you should #Autowire them and let Spring inject it for you.
Here’s an example of two dependencies injected via constructor:
#Component
public class Car {
private final Engine engine;
private final Transmission transmission;
#Autowired
public Car(Engine engine, Transmission transmission) {
this.engine = engine;
this.transmission = transmission;
}
}
Note that your class must be a Spring Component itself in order for the injection to occur.
There are actually three types of dependency injection in Spring: constructor, field and setter injection. Spring team recommends using the constructor based approach, and this post brings very nice arguments to this point: https://blog.marcnuri.com/field-injection-is-not-recommended/
You can refer to this link for more information on constructor-based injection: https://www.baeldung.com/constructor-injection-in-spring

Spring integration test & set field to controller

I am trying to create my first integration test, inspiring myself from the jhipster project.
In my setup, i use that kind of code:
CampaignController campaignController = new CampaignController();
ReflectionTestUtils.setField(campaignController, "securityService", securityService);
ReflectionTestUtils.setField(campaignController, "campaignService", campaignService);
ReflectionTestUtils.setField(campaignController, "messageService", messageService);
MockMvc restMvcCampaignController = MockMvcBuilders.standaloneSetup(campaignController).setMessageConverters(TestUtil.getCustomJsonMessageConverter()).build();
RestAssuredMockMvc.mockMvc(restMvcCampaignController);
Services are autowired classes.
I would like to know if "ReflectionTestUtils.setField" is a good practice or if there is anything else better I could use ?
Thank you
It's not a good practice. Instead of making it impossible to set the dependencies (other then by reflection), inject the dependencies via a constructor. For example
#Controller
public class Controller {
private CampaignService campaignService;
#Autowired
public Controller(CampaignService campaignService, MessageService messageService) {
//bind fields
}
}
Now you can instantiate the controller easily from the test.

Injecting dependencies using #Autowired into objects created with "new ..."

I have a problem with injecting a bean into a helper class. It works basically like this: I create an object in the page constructor that does some work, returns some data and I show these on the page. In this helper object, a service should be injected via #Autowired annotation. However, I always get a null pointer exception when I use it. I also tried #SpringBean but it didn't help. On the other hand, when I inject this service directly into the page with #SpringBean, it's accessible and works fine. Do you know where the problem is?
This is the page:
public class Page extends BasePage {
public Page() {
HelperObject object = new HelperObject(new Application("APP_NAME"));
String result = object.getData();
add(new Label("label", result));
}
}
Helper object:
public class HelperObject {
private Application app;
#Autowired
private Service service;
public HelperObject(Application app) {
this.app = app;
}
public String getData() {
// use service, manipulate data, return a string
}
}
You can inject dependencies into non-Spring-non-Wicket-new-created objects using #SpringBean by calling InjectorHolder.getInjector().inject(this); in its constructor.
For example:
class MyPojo {
#SpringBean
MyDumbDAO dao;
MyPojo() {
InjectorHolder.getInjector().inject(this);
}
void justDoIt() {
dao.duh(); // dao is there!
}
}
Note that it will only work if called within a Wicket-managed request. If not (ie, if it's a Quartz job, or a Filter executed before Wicket's), the Application instance will not be available, and the injector won't know how to get the dependencies.
Another solution is to use Spring's #Configurable. It uses AspectJ to intercept creation of annotated objects, and inject its dependencies, even if you instantiate them directly with new (or some other framework, like Hibernate, creates them internally). But this requires runtime or build-time (works better for me) bytecode manipulation, which may be too much magic for some people.
#SpringBean only injects dependencies into classes that inherit from Wicket's Component. #Autowired only injects dependencies into classes created by Spring itself. That means you can't automatically inject a dependency into an object you create with new.
(Edit: you can also add a #SpringBean injection to your class by injecting in the constructor:
InjectorHolder.getInjector().inject(this);)
My normal workaround for this is to use my application class to help. (I'm a little puzzled by your use of new Application(...). I assume this isn't actually org.apache.wicket.Application.) For example:
public class MyApplication extends AuthenticatedWebApplication implements
ApplicationContextAware {
private ApplicationContext ctx;
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.ctx = applicationContext;
}
public static MyApplication get() {
return (MyApplication) WebApplication.get();
}
public static Object getSpringBean(String bean) {
return get().ctx.getBean(bean);
}
public static <T> T getSpringBean(Class<T> bean) {
return get().ctx.getBean(bean);
}
....
}
In my Spring application context:
<!-- Set up wicket application -->
<bean id="wicketApplication" class="uk.co.humboldt.Project.MyApplication"/>
My helper object then looks up the service on demand:
public class HelperObject {
private Service getService() {
return MyApplication.getSpringBean(Service.class);
}
The best practice would be to create your objects via a factory bean (that has those properties injected by Spring, and have that factory inject those properties to objects it spawns - pure IoC).
You should really avoid using SpringContext all over the place (or any other similar solution for that matter).
Here is a partial list of reasons:
Your code gets coupled with Spring way too much (low-cohesion).
You mix plumbing code with the business-logic.
Your code is less readable.
It's less maintainable (e.g., changing the name of the service bean would lead to code modification - this violates SRP & OCP).
It's less testable (e.g., you need the Spring framework to test it).

Categories

Resources