If class A depend on class B , pass the declaration of class B to third party to declare
Example: If a graduate want to find a suitable job , he should find the agent to help him to look for his suitable job according to his abilities, instead of every student find for the same job.
Dependency injection is a one of the example of inversion of control
Without IOC
public class Graduate {
private Programmer programmer;
}
// That assume all the graduate must find a programmer job, which is strongly coupled
With IOC
public class Graduate{
private Job job;
public void setJob(Job job){
this.job = job;
}
}
// The job class is an interface;
// The job of the graduate will handled by another class(e.g Main class)
// which make the graduate loosely coupled with Job class
Dependency Injection
Initial
public class Lesson{
private Student student;
public Lesson(){
this.student = new Student();
}
}
Dependency Injection (by constructor)
public class Lesson{
private Student student;
public Lesson(Student exampleStudent){
this.student = exampleStudent;
}
}
Dependency Injection (by setter)
public class Lesson{
private Student student;
public void setStudent(student exampleStudent){
this.student = new Student();
}
}
Initially, lesson class is fixed with a specific student class. If we declare new Lesson class, the student must be the same as every lesson class, which will cause out coupling.
By using dependency injection, lesson class and student will be independent to each other.
Why Spring?
It has strong IOC container (Application Context) which manage and create the beans
Developer can do dependency injection easily by using the bean of container
Structure of Java Spring
Data Access Integration
Provide several popular API , such as hibernate, JPA
Make the syntax of connecting database simpler
Web
Provide several web function, such as file reader
Define Controller, Model and View
Core
Application Context Container or Bean Factory Container is a container to contain the bean factory which is a xml file traditionally
Application Context Container
package com.yiibai;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class MainApp {
public static void main(String[] args) {
XmlBeanFactory factory = new XmlBeanFactory
(new ClassPathResource("Beans.xml"));
HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");
obj.getMessage();
}
}
Bean Factory Container
package com.yiibai;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class MainApp {
public static void main(String[] args) {
XmlBeanFactory factory = new XmlBeanFactory
(new ClassPathResource("Beans.xml"));
HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");
obj.getMessage();
}
}
Bean
Introduction
Bean can be instantiated as a instance of the class, which is similar with the below syntax to declare the new instance - sample Student
Student sampleStudent = new Student("Chan Tai Man", 12);
Bean can rely on another beans by using auto wire
Example of creating bean by using traditional xml
// HelloWorld.java
package com.yiibai;
public class HelloWorld {
private String message;
public void setMessage(String message){
this.message = message;
}
public void getMessage(){
System.out.println("Your Message : " + message);
}
}
// MainApp.java
package com.yiibai;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("Beans.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
}
}
package com.yiibai;
public class TextEditor {
private SpellChecker spellChecker;
// a setter method to inject the dependency.
public void setSpellChecker(SpellChecker spellChecker) {
System.out.println("Inside setSpellChecker." );
this.spellChecker = spellChecker;
}
// a getter method to return spellChecker
public SpellChecker getSpellChecker() {
return spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}
In text editor, it will look for the bean containing spell checker type or the same name automatically and inject into text editor
By Type (Annotation)
package com.yiibai;
import org.springframework.beans.factory.annotation.Autowired;
public class TextEditor {
private SpellChecker spellChecker;
@Autowired
public void setSpellChecker( SpellChecker spellChecker ){
this.spellChecker = spellChecker;
}
public SpellChecker getSpellChecker( ) {
return spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}
In text editor, it will look for the bean containing spell checker type automatically and inject into text editor
If spellchecker is a interface , make sure that it should be implemented by one class only
By Name (Annotation)
If a spell checker may be a interface and implement by several class, so we should look for the bean according to the name of the bean
package com.yiibai;
import org.springframework.beans.factory.annotation.Autowired;
public class TextEditor {
private SpellChecker spellChecker;
@Resource(name = "sampleSpellerChecker")
public void setSpellChecker( SpellChecker spellChecker ){
this.spellChecker = spellChecker;
}
public SpellChecker getSpellChecker( ) {
return spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}
Configuration
In spring, we can make good use of annotation instead of configure xml file
Annotation
package com.yiibai;
import org.springframework.context.annotation.*;
@Configuration
public class HelloWorldConfig {
@Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
Initially, we need to declare each bean one by one. Now, we can make good use of annotation to mark the class as a component, and perform scanning on spring container which can be in xml or java code , that will register the bean automatically for class who is marked as a component
@Configuration
@ComponentScan("com.luv2code")
@PropertySource("classpath:sport.properties")
public class SportConfig {
@Bean
public FortuneService normalFortuneService(){
return new NormalFortuneService();
}
@Bean
public Coach swimCoach(){
return new SwimCoach(normalFortuneService());
}
}
There are common 5 annotations to create beans
Component
It can be used in different layers
Not recommended to use
@Component
public class UserComponentImpl implements IUser {
private String name = "UserComponentImpl";
public String get() {
return name;
}
}
@Component(value="componentBeanId")
public class UserComponentImplWithParam implements IUser {
private String name = "UserComponentImplWithParam";
public String get() {
return name;
}
}
used to handle URL and can used to return jsp file
Example 1 (Return jsp File)
@Controller
@RequestMapping("/test/{id}")
public class PathVariableTest {
@RequestMapping("/{name}/get.do")
public String get (@PathVariable("id") Integer index, Model model) {
model.addAttribute("id", index);
return "/index";
}
}
Example 2 (return string or other type)
@Controller
@GetMapping("/bi")
public class ResponseBodyTest {
@RequestMapping("/login")
@ResponseBody
public String get () {
return "Hello Spring Boot!";
}
}
RestController
It is one part of the controller
act as a api end point and must be return in string or other type
RestController = Controller + ResponseBody
@RestController
@RequestMapping("/bi")
public class ResponseBodyTest {
@GetMapping("/login")
public String get () {
return "Hello Spring Boot!";
}
}