# Spring notes
DI can be done with those 3 types of configuration:
1. Full XML Config
2. XML Component Scan
3. Java Configuration Class
## 1) DI with applicationContext
### Setter injection
**With a file.properties:**
```xml=
<context:property-placeholder location="classpath:toto.properties"/>
...
<bean id="idOfClass" class="pathToClass">
<property name="propertyNameOfDependency" ref="idOfDependency"/>
<property name="email" value="${toto.email}"/>
...
</bean>
```
NB: The properties need setter methods!
Cause Spring will look out for them in order to inject the properties.
:warning: How does Spring find those setters? --> by the name of the method! Thus the name **must** be `setFooProperty`
### Constructor injection
```xml=
<constructor-arg ref="idOfDependencyToInject"/>
```
### Scopes
```java=
context.getBean("<name_of_bean_in_context>", <interface>.class)
```
To modify a bean scope: just add a "scope" tag and singleton or prototype.
- `singleton`: default, only one instance of the object is created
- `prototype`: a new object is created for each request (the request being `context.getBean()`)
### Lifecyles
Custom code during bean initalization/destruction = **hooks** (you can hook in code)
To add hooks to a bean initalization/destruction: just add a "`init-method`" or "`destroy-method`" tag and a name of method.
```xml=
<bean id="myDanceCoach" class="com.luv2code.springdemo.DanceCoach" init-method="startup" destroy-method="destroy">
```
NB: prototype scope --> no destruction method!
___
## 2) DI with annotations
Annotate a bean instead of declaring it into `applicationContext.xml`:
```java=
@Component("thatSillyCoach")
```
```java=
@Component // Default id = name of the class with the first letter lower-cased (BigRectangle --> bigRectangle)
```
together with the following line into the `applicationContext.xml` (enables component scanning through a package)
```xml
<context:component-scan basepackage="com.luv2code.springdemo"/>
```
### Autowiring
Autowiring = injection
- Spring looks for a class/Bean (annotated with `@Component`) that matches the property (type of class or interface)
- Spring injects it automatically
#### Constructor injection
To inject into constructor, just add `@Autowired` above the construtor in which you want to inject.
NB: Starting with Spring 4.3, if a class, which is configured as a Spring bean, has only one constructor, the @Autowired annotation can be omitted and Spring will use that constructor and inject all necessary dependencies.
Regarding the default constructor: You either need the default constructor, a constructor with the @Autowired annotation when you have multiple constructors, or only one constructor in your class with or without the @Autowired annotation.
#### Setter injection
To inject into a property (setter injection), just add `@Autowired` above the setter of the given properties you want to inject.
NB: You do not have to call your setter method exactly `setFooProperty`. You're free to call it whatever you want.
#### Field injection
- Uses Java reflexion
- Fields are injected **right after construction of a bean**, before any config methods are invoked. Such a config field **does not have to be public**.
To do field injection, just add `@Autowired` above a property you want to inject.
NB: The reasons why field injection is frowned upon are as follows:
- You **cannot create immutable objects**, as you can with constructor injection (since it's injected after construction, it cannot be final, lazy at least ?)
- Your classes have **tight coupling with your DI container** and cannot be used outside of it
- Your classes **cannot be instantiated** (for example in unit tests) without reflection. You need the DI container to instantiate them, which makes your tests more like integration tests
#### Multiple implementations of a dependency (no unique bean)?
Together with the @Autowired annotation, add the following
```java=
@Qualifier("classNameOfComponent")
```
#### To inject properties for file.property
```java=
@Value("${foo.email}")
private String email;
@Value("${foo.team}")
private String team;
```
#### Scope
```java=
@Component
@Scope("prototype")
```
#### Hooks
```java=
@Component
public class Toto() {
...
@PostConstruct
private void startup() {}
@PreDestroy
public void destroy() {}
}
```
## 3) DI with Java Configuration Class
Add a dedicated class:
```java=
@Configuration
@ComponentScan("com.luv2code.springdemo") // Optional if you declare the bean with @Bean
public class SportConfig {}
```
Replace the `ClassPathXmlApplicationContext` with
```java=
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SportConfig.class);
```
NB: Spring Boot introduces the `@SpringBootApplication `annotation. This single annotation is equivalent to using `@Configuration`, `@EnableAutoConfiguration`, and `@ComponentScan`.
### Parallel Spring/Hilt
| Spring | Hilt |
|:----------------------------------:|:--------------------------------------:|
| @Bean | @Provides |
| @Autowired | @Inject |
| @Scope("singleton") | @Singleton |
| @Qualifier("randomFortuneService") | @<Annotation given when bean declared\> |
Example:
```java=
public class SportConfig {
@Bean
public Random random() {
return new Random();
}
// Returns FortuneService
@Bean
public FortuneService randomFortuneService() {
return new RandomFortuneService(random());
}
// Returns also FortuneService
@Bean
public FortuneService happyFortuneService() {
return new HappyFortuneService();
}
@Bean
public TennisCoach tennisCoach() {
return new TennisCoach(randomFortuneService());
}
}
```
```java=
// Injection
public TennisCoach(@Qualifier("randomFortuneService") FortuneService fortuneService) {
this.fortuneService = fortuneService;
}
```
```kotlin=
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@AuthInterceptorOkHttpClient
@Provides
fun provideAuthInterceptorOkHttpClient(
authInterceptor: AuthInterceptor
): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(authInterceptor)
.build()
}
@OtherInterceptorOkHttpClient
@Provides
fun provideOtherInterceptorOkHttpClient(
otherInterceptor: OtherInterceptor
): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(otherInterceptor)
.build()
}
}
```
```kotlin=
class ExampleServiceImpl @Inject constructor(
@AuthInterceptorOkHttpClient private val okHttpClient: OkHttpClient
) : ...
```
### Use property file
`@PropertySource("classpath:file.properties")` into the class configuration.
## MVC
`/WEB-INF/view/show-student-list.jsp`
prefix/../suffix
JSP = JavaServer Pages: enables you to write dynamic, data-driven pages for your Java web applications
### Bind a form
```java=
@GetMapping("/greeting")
public String greeting(
@RequestParam(name = "name", required = false, defaultValue = "World") String name, Model model) {
model.addAttribute("message", name.toUpperCase());
return "greeting";
}
```
```htmlmixed=
<p th:text="'Hello ' + ${param.name} + '!'"></p>
```
```htmlmixed=
<p th:text="'Hello ' + ${message} + '!'"></p>
```
spring web flux
web flux ! notion reactive