Dependency Injection - Spring
Tags: java, spring
Published: 2021-10-09 02:59:09

### Basics
- Spring has lot of modules
- start.spring.io lists many spring modules which you can configure
- spring boot is useful to build RESTfull web services. It makes developing spring applications easy by auto configuring default components. It is opinionated framework
- fat jar -> also includes tomcat. better solution if you want to deploy on cloud platforms

### Dependency Injection
- Assume mail sender example, where we can have mailSender of type SMTP, POPM or MockMail. 
- We can have an interface MailSender which defines the common functionality and we implement the interface in SMTP, POPM or Mock class.
- **Problem: object creation will be like: **
	- private MailSender  = new SMTPMailSender()
	- private MailSender  = new POPMMailSender()
	- private MailSender  = new MockMailSender()
	- we need to hardcode the type while creating object
	- can we automate this?
	- Add @Component annotation to any class which implements MailSender
	- Add @Autowired annotation when creating object
	- **how does it work:**
		- When application starts all the beans gets setup
			- Beans: annotations at top level, whose object will be created and stored in *Application Context*
			- Beans examples: @Component, @RestController
		- When application is running and when we create objects variables for which we have annotations like @Autowired. Objects which were already created from application context are assigned to current variables. 
		- i.e those objects from application context are injected into these variables and hence dependency injection
- @Autowired also works on methods(setters, constructors, getters, any methods..)
- **Multiple beans problem:** when we create two classes from same interface and add @component annotation to both classes, and create object using interface using @autowired annotation, spring will be confused to choose between beans
	- one solution is to use camel-case variable names while creating objects which resemble the name of the class you want (ex: smtpMailSender)
	- you can also add name param to @component -> @component("mockMail"), and create object using the name mockMail
	- use extra @primary annotation, the bean which has this will get preference
	- you can also use @qualifier annotation to class, and also use @qualifier in setter or constructor, ...etc
- Prefer constructor injection
- @resource and @inject are similar to @autowired, but @autowired is very powerful, so use @autowired
- Specializations of @component annotations
	- @Controller
	- @Service
	- @Repository
	- @Configuration
	- @SpringBootApplication(scanBasePackageClasses = {default.class, abc.class}) - scans through the package and puts any dependency injection components into application context
	- @RestController
	- ..... many others
- what if you import a dependency and you have to create object from there, you cannot add @component annotation dependency package
	- Create a new config class, which has methods to return objects from the external dependency
	- the new config class must have @Configuration annotation
	- and methods must have @Bean configuration
	- names of the methods can be used for object variable names
- use @Value annotation to access variables from .properties or .yaml files
- an external config file takes more preference over internal config(application.properties)
- **Profiles: **A spring application can be configure to behave differently in different environments using profiles
	- ex environments: dev, test, prod
	- provide in application.properties:
		- spring.profiles.active: book, dev
	- you can also use particular beans in particular environments!
		- just	use @Profile("envName"), can accepts bool, !envName
	- @Conditional annotation, include or exclude beans based on arbitrary conditions
		- @ConditionalOnClass, OnProperty, OnMissingBean ..etc
		- configure bean based on presence of application property => @ConditionalOnProperty
- In @Configuration classes, when we try to create same bean again from some method, spring still returns the cached bean only.
	- Caching does not happen when we use @Component annotation 
- Always use @Configuration Classes

visit my personal blog: https://rahilrehan.github.io/