# 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