Spring Core Interview - tarunchhabra/parakalo GitHub Wiki
IOC-
Inversion of Control is a principle in software engineering by which the control of objects or portions of a program is transferred to a container or framework.
IOC can be achieved through various mechanisms such as: Strategy design pattern, Service Locator pattern, Factory pattern, and Dependency Injection (DI).
The advantages of Spring based architecture:
decoupling the execution of a task from its implementation
making it easier to switch between different implementations
greater modularity of a program
greater ease in testing a program by isolating a component or mocking its dependencies and allowing components to communicate through contracts
Dependency Injection
Dependency Injection, is a general concept stating that you do not create your objects manually but instead describe how they should be created. An IoC container will instantiate required classes.
DI is a pattern through which to implement IoC, where the control being inverted is the setting of object's dependencies.
Dependency: An object usually requires objects of other classes to perform its operations. We call these objects dependencies. Injection: The process of providing the required dependencies to an object.
The act of connecting objects with other objects, or “injecting” objects into other objects, is done by an assembler rather than by the objects themselves.
DI results in Modularity and Loose coupling between class and its dependencies.
The Spring IoC Container
In the Spring framework, the IoC container is represented by the interface ApplicationContext. The Spring container is responsible for instantiating, configuring and assembling objects known as beans, as well as managing their lifecycle.
The Spring framework provides several implementations of the ApplicationContext interface — ClassPathXmlApplicationContext and FileSystemXmlApplicationContext for standalone applications, and WebApplicationContext for web applications.
In order to assemble beans, the container uses configuration metadata, which can be in the form of XML configuration or annotations.
Dependency Injection in Spring can be done through constructors, setters or fields.
** How Can We Inject Beans in Spring?**
A few different options exist:
Setter Injection Constructor Injection Field Injection (autowire)
The configuration can be done using XML files or annotations.
## Constructor Injection
In constructor-based injection, the dependencies required for the class are provided as arguments to the constructor
Constructor-Based Dependency Injection within Spring – means that required components are passed into a class at the time of instantiation.
In the case of constructor-based dependency injection, the container will invoke a constructor with arguments each representing a dependency we want to set.
@Component class Cake {
private Flavor flavor;
Cake(Flavor flavor) { Objects.requireNonNull(flavor); this.flavor = flavor; }
Flavor getFlavor() { return flavor; } ... }
Before Spring 4.3, we had to add an @Autowired annotation to the constructor. With newer versions, this is optional if the class has only one constructor.
In the Cake class above, since we have only one constructor, we don’t have to specify the @Autowired annotation. Consider the below example with two constructors:
@Component class Sandwich {
private Topping toppings; private Bread breadType;
Sandwich(Topping toppings) { this.toppings = toppings; }
@Autowired Sandwich(Topping toppings, Bread breadType) { this.toppings = toppings; this.breadType = breadType; } ... }
When we have a class with multiple constructors, we need to explicitly add the @Autowired annotation to any one of the constructors so that Spring knows which constructor to use to inject the dependencies. or we can add @Autowired(required=false) and spring will try to satisfy as many dependencies as possible.
## Setter-Based Dependency Injection
For setter-based DI, **the container will call setter methods of our class, after invoking a no-argument constructor **or no-argument static factory method to instantiate the bean.
In setter-based injection, we provide the required dependencies as field parameters to the class and the values are set using the setter methods of the properties. We have to annotate the setter method with the @Autowired annotation.
Constructor-based and setter-based types of injection can be combined for the same bean.
Which Is the Best Way of Injecting Beans and Why?
The Spring documentation recommends using constructor-based injection for mandatory dependencies, and setter-based injection for optional ones.
**Why constructor-based injection for mandatory dependencies? **
All Required Dependencies Are Available at Initialization Time We create an object by calling a constructor. If the constructor expects all required dependencies as parameters, then we can be 100% sure that the class will never be instantiated without its dependencies injected.
The IoC container makes sure that all the arguments provided in the constructor are available before passing them into the constructor. This helps in preventing the infamous NullPointerException.
Constructor injection helps us to identify if our bean is dependent on too many other objects. If our constructor has a large number of arguments this may be a sign that our class has too many responsibilities.
Constructor injection is extremely useful since we do not have to write separate business logic everywhere to check if all the required dependencies are loaded, thus simplifying code complexity.
Constructor injection and Immutability & Multithreading
Constructor injection allows injecting values to immutable fields and makes testing easier. Constructor injection helps in creating immutable objects because a constructor’s signature is the only possible way to create objects. Once we create a bean, we cannot alter its dependencies anymore. With setter injection, it’s possible to inject the dependency after creation, thus leading to mutable objects which, among other things, may not be thread-safe in a multi-threaded environment and are harder to debug due to their mutability.
By using setter injection, you can override certain dependency which is not possible with constructor injection because every time you call the constructor, a new object is gets created._
What About Optional Dependencies? With setter injection, Spring allows us to specify optional dependencies by adding @Autowired(required = false) to a setter method. This is not possible with constructor injection since the required=false would be applied to all constructor arguments.
We can still provide optional dependencies with constructor injection using Java's Optional type.
Field-Based Dependency Injection
With field-based injection, Spring assigns the required dependencies directly to the fields on annotating with @Autowired annotation.
In case of Field-Based DI, we can inject the dependencies by marking them with an @Autowired annotation
public class Store { @Autowired private Item item; } While constructing the Store object, if there's no constructor or setter method to inject the Item bean, the container will use reflection to inject Item into Store.
Drawbacks of field based:
This method uses reflection to inject the dependencies, which is costlier than constructor-based or setter-based injection.
What will happen if we add @Autowired to both, a field and a setter? Which method will Spring use to inject the dependency?
@Component class Pizza {
@Autowired private Topping toppings;
Topping getToppings() { return toppings; }
@Autowired void setToppings(Topping toppings) { this.toppings = toppings; } }
In the above example, we have added the @Autowired annotation to both the setter and the field. In this case, Spring injects dependency using the setter injection method.
Note that it’s bad practice to mix injection types on a single class as it makes the code less readable.
Autowiring Dependencies
Wiring allows the Spring container to automatically resolve dependencies between collaborating beans by inspecting the beans that have been defined. @Autowired can be used for-
Setter Injection Constructor Injection Field Injection
There are four modes of autowiring a bean using an XML configuration:
no: the default value – this means no autowiring is used for the bean and we have to explicitly name the dependencies byName: autowiring is done based on the name of the property, therefore Spring will look for a bean with the same name as the property that needs to be set
byType: similar to the byName autowiring, only based on the type of the property. This means Spring will look for a bean with the same type of the property to set. If there's more than one bean of that type, the framework throws an exception. constructor: autowiring is done based on constructor arguments, meaning Spring will look for beans with the same type as the constructor arguments
For example, let's autowire the item1 bean defined above by type into the store bean:
@Bean(autowire = Autowire.BY_TYPE) public class Store {
private Item item;
public setItem(Item item){
this.item = item;
}
} We can also inject beans using the @Autowired annotation for autowiring by type: public class Store {
@Autowired
private Item item;
} If there's more than one bean of the same type, we can use the @Qualifier annotation to reference a bean by name:
public class Store {
@Autowired
@Qualifier("item1")
private Item item;
}
Autowire - In case of disambiguation in args, Spring resolves each argument primarily by type, followed by name of the attribute and index .
type -> name -> constructor
@Autowire annotation has order of precedence in case of both setter and field injection:
Match by Type Match by Qualifier Match by Name
how to use the @Autowired annotation in abstract classes.
First, an abstract class isn't component-scanned since it can't be instantiated without a concrete subclass.
When we use @Autowired on a setter method, we should use the final keyword, so that the subclass can't override the setter method. Otherwise, the annotation won't work as we expect.
We can't use @Autowired on a constructor of an abstract class.
Spring doesn't evaluate the @Autowired annotation on a constructor of an abstract class. Instead, we should use @Autowired on the constructor of the subclass.
https://www.baeldung.com/spring-autowired-abstract-class
Circular Dependencies in Spring
when having a circular dependency, Spring cannot decide which of the beans should be created first, since they depend on one another. In these cases, Spring will raise a BeanCurrentlyInCreationException while loading context.
Constructor injection (from the definition) does not allow you to create circular dependencies between beans. This limitation is actually an advantage of constructor injection - Spring can resolve circular dependencies when setter injection is used without you even noticing.
It can happen in Spring when using constructor injection; if you use other types of injections you should not find this problem since the dependencies will be injected when they are needed and not on the context loading.
Solution:
Setter dependency- If Object A and B are dependent each other i.e A is depends ob B and vice-versa. Spring throws ObjectCurrentlyInCreationException while creating objects of A and B bcz A object cannot be created until B is created and vice-versa. So spring can resolve circular dependencies through setter-injection. Objects constructed before setter methods invoked. https://www.baeldung.com/circular-dependencies-in-spring
Use @Lazy
Use Field Injection
Lazy Initialized Beans
By default, the container creates and configures all singleton beans during initialization. To avoid this, you can use the lazy-init attribute with value true on the bean configuration:
As a consequence, the item1 bean will be initialized only when it's first requested, and not at startup. The advantage of this is faster initialization time, but the trade-off is that configuration errors may be discovered only after the bean is requested, which could be several hours or even days after the application has already been running.
https://www.baeldung.com/inversion-control-and-dependency-injection-in-spring
https://www.baeldung.com/constructor-injection-in-spring https://reflectoring.io/constructor-injection/ https://www.baeldung.com/spring-annotations-resource-inject-autowire