Could someone please explain to me why do we need to use the spring's dependency injection when you can just import a java class like:
import com.package.somejavaclass
I just wonder why?
DI and IoC
Dependency Injection (and Inversion of Control) have nothing to do with import. Dependency injection allows you to make runtime decisions instead of compile-time decisions. For example, how your class gets a database Connection. That is configuration over hard-coding.
import
The import statement allows you to not specify the fully-qualifed name of a class. That is, without import java.util.Date; you can still (for example)
System.out.println(new java.util.Date());
Dependency Injection is used to remove need for the code changes and make it possible using configuration only.
I.e., you have
Interface B {
//some methods
}
class X implements B{
// implement some methods of B
}
class Y implements B{
// implement some methods of B
}
// code without using Dependency Injection
class A1{
private B objB = New X();
//remaining code
}
class A2{
private B objB = New X();
//remaining code
}
Note: if you need to change for some reason objB instance with class Y, you need to make code changes in both classes A1 and A2.
// code using Dependency Injection
class A1{
#Autowired
private B objB;
//remaining code
}
class A2{
#Autowired
private B objB;
//remaining code
}
Here you just need to change configuration of creating instances for interface B and change required class from X to Y that's it.
No changes in any of java classes (here A1 and A2).
Import - is static import,
Dependency Injection - dynamic import
In addition to #Nirav Patel answer, I would like to add a scenario. If we want to have a different implementation in different environment (Dev/QA/UAT/Prod), you don't need to change the code, you can achieve it using DI and also changing the configuration in that environment.
Watch this video, if you need a detailed explanation
https://www.udemy.com/spring-framework-video-tutorial/learn/v4/t/lecture/4635190
(By the way, it's a free course in Udemy)
Instructor sends a mock email in dev and real email using smtp, just by changing the configuration.
Related
I have created this class:
import org.springframework.stereotype.Component;
...
#Component("notTheNameTestMe") //shouldnt this only work with testMe ?
public class TestMe {
public void showMsg() {
System.out.println("Autowiring works");
}
}
And I'm using it this way in a second class (or better: controller):
import com.example.TestMe; //shouldnt this be not necessary with autowire? But getting error else...
...
#Autowired
private TestMe testMe;
...
this.testMe.showMsg();
But this works perfectly (so maybe Im not really using autowire here?), it even works if I rename the whole TestMe class to TestMeSomething (if I adjust the import in the second class)
I dont really understand what #Autowired does. I thought it just scans for SpringBoot Components (which are named by the string in #Component() and when it finds a match it Injects the dependancy. But in my example the match is impossible and I still can see the message "Autowiring works" in the console. This shouldnt be like this if I would really use autowire here or? What am I understanding in a wrong way? What is the difference to using new TestMe() then? I have the dependancy already with the import or? So not a real dependancy injection, or?
Spring is not operating on the name in the #Component annotation. Rather it's using the name of the class. It's simply finding a class named TestMe because that's the type of the variable you've annotated with #Autowired.
I'm new to specifying resource routes in Java, and I'm having issues specifying the route. So far I have one Class which simply extends Application, and one class that reacts to input. What are the routing requirements for these classes? My code below does not work and im trying to figure out why. I've tried to find sources for these, but haven't had much luck.
Can I just use a / for the ApplicationPath? All this class does is extend Application so it can find routes.
Example:
package com.sentiment360.helloworld;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
/**
* JAXActivator is an arbitrary name, what is important is that javax.ws.rs.core.Application is extended
* and the #ApplicationPath annotation is used with a "rest" path. Without this the rest routes linked to
* from index.html would not be found.
*/
#ApplicationPath("/")
public class JAXActivator extends Application {
}
Does each class need to have a declared #Path (or can they all be #Stateless)?
#Path("/helloservice")
public class HelloService {
private static Logger _logger;
public HelloService(){
_logger = Logger.getLogger(HelloService.class.getName());
}
private Connection conn() throws SQLException {...}
}
The short version for #1 is yes.
BUT: behavior is implementation dependent. See https://stackoverflow.com/a/16747253/1063501 for a thorough explanation.
As for #2, yes, you generally need to specify a #Path for every endpoint you want. The fact that it is #Stateless is irrelevant as you'll need a way to address it.
Given this code:
package my.pkg;
import com.google.common.util.concurrent.Service;
class Test implements Service {
public static void main(String... a) {
System.out.println(Listener.class);
}
// method implementations omitted for brevity
}
And given there's one Listener class in my.pkg, and one as an inner class in the Service class I'm importing.
I would expect the package local class to 'win' here, since I'm not referring to Service.Listener.class or explicitly importing the inner class. Apparently, IntelliJ expects the same thing, since if I explicitly add import my.pkg.Listener;, it is automatically removed as being redundant. However, when compiling and running this code (Gradle 2.14.1 and openjdk 1.8.0_91, if that matters), it's very clear the inner class is winning.
How do I get this code to use the class in my.pkg? Explicitly adding the import doesn't work, since my IDE removes it. I'd also prefer not to use full class names (my.pkg.Listener) everywhere in the class.
I'm using the spring state machine and want to add on functionality to transitions and state changes using #WithStateMachine, #OnTransition and #OnStateChanged to keep the class with #EnableStateMachine as simple as possible. I never got it to work though and after some trial and error I realised that the #WithStateMachine bean has to be created before the state machine but that dependency isn't automatically solved.
The interesting parts of my project basically boils down to the following:
package org.myorg.a
#Component
public class MyComponent {
#Autowired
StateMachine<States, Events> sm;
}
package org.myorg.b
#WithStateMachine
public class Listener {
#OnTransition
public void anyTransition() {}
}
MyComponent and therefore the state machine will be created before the Listener because Spring will look in package a before package b and in effect none of the methods in class Listener will be associated with the state machine and the anyTransition method will never be called.
The only two solutions to this that I can think of is
Rename the packages
Annotate the #EnableStateMachine class with #DependsOn and explicitly depend on all #WithStateMachine classes
In my opinion neither of those two solutions are good. Does anyone have a better way to solve this?
Hopefully this just got fixed in https://github.com/spring-projects/spring-statemachine/issues/232.
I am just testing dynamic class load and am doing this:
package P1;
public class Class1
{
public static void main(String[] args)
{
Bird myBird = null;
String myClassName = "P2.Bird";
Class x = Class.forName(myClassName);
myBird = (Bird)x.newInstance();
}
}
Bird is a class from package P2, and Class1 is from P1. What should I add in the code to make this work, as the String myClassName... line shows an error (class not found). I tried the same code after moving Bird in package P1, even then it doesn't work.
Related question: Why would someone use dynamic class load, does it have any advantages? It's much simpler(at least for me at first glance) to just use the "new" operator for static class loading, and in that case I know how to refer the class from a different package. Many thanks!
For the answer to your first question try mentioning full Package name. I have tried it and it works
Your Bird class provides a default public constructor with no arguments?
Dynamic class loading can be useful for example to specify the class you want to use in a configuration file (you will come across that if you ever use log4j, or other libraries that allow the use of your own implementation to one of their interfaces). In that case, the library does not know about which class you will use, and you don't have to write code to initialise the library (which would be the alternative to dynamic class loading, but which is less convenient)