Java/Spring - Dependency injection
Published on
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
- When application starts all the beans gets setup
- @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