Spring Basics
the basic java engineering best practice is that we can use Polymorphism to implement the method in the subclass. But this is still hardcoded. How to improve it so that we can extract the config information and implement the corresponding action.
Spring Container
- Inversion of Control (create and manage objects)
- Dependency Injection (Inject object's dependencies)
Three ways of configuring the Spring Container:
XML configuration file(legacy)
- Inversion of Control:
- Configure your Spring Beans
- eg. applicationContext.xml
- <beans ...>
- <bean id="myCoach" class="com.luv2code.springdemo.BaseballCoach" </bean>
- </beans>
- <beans ...>
- eg. applicationContext.xml
- Create a Spring Container
- Spring container is generally known as ApplicationContext
- Specialized implementations
- ClassPathXmlApplicationContext
- AnnotationConfigApplicationContext
- ...
- e.g. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContex(".---.xml");
Retrieve Beans from Spring Container
- e.g. Coach theCoach = context.getBean("myCoach", Coach.class); // Coach.class is the interface..
java file: public class HelloSpringApp { public static void main(String[] args) { // load the spring configuration file ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // retrieve bean from spring container Coach theCoach = context.getBean("myCoach", Coach.class); // call methods on the bean System.out.println(theCoach.getDailyWorkout()); // close the context context.close(); } } xml file: <beans xmlns= ....> <bean id="myCoach" class="com.luv2code.springdemo.TrackCoach"> </bean> </beans>
note that: why do we specify the Coach interface in getBean()? answer: when we pass the interface to the method, behind the scenes Spring will cast the object for you.
XML configuration for dependency injection
"dependency" same thing as "helper objects"
there are two most common types of injection with Spring
Constructor Injection
Setter Injection
"auto-wiring" in the Annotations section later
Constructor Injection
Define the dependency interface and class
- create FortuneService.java and HappyFortuneService.java
Create a constructor in your class for injections
in the baseballCoach
e.g. the goal is to create a constructor and try to pass in a reference to my HappyFortuneService
public class BaseballCoach implements Coach { // define a private field for the dependency private FortuneService fortuneService; // define a constructor for dependency injection public BaseballCoach(FortuneService theFortuneService) { fortuneService = theFortuneService; } ... }
Configure the dependency injection in Spring config file
first, define dependency / helper
second, inject the dependency / helper using "constructor injection"
e.g. the goal is to pass in a reference to my HappyFortuneService.
<bean id="myFortune" class="com.luv2code.springdemo.HappyFortuneService"> </bean> <bean id="myCoach" class="com.luv2code.springdemo.BaseballCoach"> <!-- set up constructor injection --> <constructor-arg ref="myFortune"/> // means put the happyfortuneService to the baseballcoach class </bean>
note that: the key is that Spring will do this work for you in the background and Spring's object factory when you wanna create an object and they inject the dependencies,
Setter Injection
create setter method in your class for injections
// our setter method public void setFortuneService(FortuneService fortuneService) { System.out.println("CricketCoach: inside setting method - setFortuneService"); this.fortuneService = fortuneService; }
configure the dependency injection in Spring config file
<bean id="myFortuneService" class="com.luv2code.springdemo.HappyFortuneService"> </bean> <bean id="myCricketCoach" class="com.luv2code.springdemo.CricketCoach"> <!-- set up setter injection --> <property name="fortuneService" ref="myFortuneService" /> </bean>
Injecting Literal values
create setter method in your class for injections
// add new fields for email address and team private String emailAddress; private String team; // create the set method for address and team public void setEmailAddress(String emailAddress) { System.out.println("CricketCoach: inside setting method - setEmailAddress"); this.emailAddress = emailAddress; } public void setTeam(String team) { System.out.println("CricketCoach: inside setting method - setTeam"); this.team = team; }
configure the injection in Spring config file
<bean id="myCricketCoach" class="com.luv2code.springdemo.CricketCoach"> <!-- set up setter injection --> <property name="fortuneService" ref="myFortuneService" /> <property name="emailAddress" value="[email protected]" /> <property name="team" value="Sunrisers Hyderabad" /> </bean>
Injecting values from a Properties File
create a Properties file e.g. sport.properties and type in [email protected]
put this at the top of the xml file
<!-- load the properties file: sport.properties -->
<context:property-placeholderlocation="classpath:sport.properties"/>
then, somewhere in the xml file, you can retrieve the value from properties file
- <propertyname="emailAddress"value="${foo.email}"/>
Bean Scope
- by default this is a singleton, but if you want to explicitly specify it,
<beans ...> <bean id="myCoach" class="com.luv2code.springdemo.TrackCoach" scope="singleton"> ... </bean> </beans>
note that, when you new a object, it just refer to the same memory
prototype scope: new object for each request
Bean lifeCycle
bean instantiated -> dependencies injected -> internal spring processing -> your custom init method -> ... -> your custom destroy method -> stop
bean custom initialization
- call custom business logic methods, or setting up handles to resources
- eg. <bean id="" class="" init-method="">
bean custom destruction
call custom business logic methods, or clean up handles to resources( db, sockets, files etc)
e.g. <bean id="" class="" destroy-method="">
Java Annotations (modern)
why we use Spring configuration with Annotations?
XML configuration can be verbose
configure your Spring beans with Annotations
Annotations minimizes the XML configuration
inversion of control
development process
Enable component scanning in Spring config file recursively
<beans ...> <context:componen-scan base-package="com.luv2code.springdemo" /> </beans>
Add the @Component Annotation to your Java classes
@Component("thatSillyCoach") public class TennisCoach implements Coach { @Override public String getDailyWorkout() { return "Practice your backhand volley"; } }
Retrieve bean from Spring container
Coach theCoach = context.getBean("thatSillyCoach", Coach.class);
Default Component Names
Autowiring
configure injection
define the dependency interface and class
FortuneService interface file public interface FortuneService { public String getFortune(); } HappyFortuneService file @Component public class HappyFortuneService implements FortuneService { @Override public String getFortune() { return "Today is your lucky day!"; } }
create a constructor in your class for injections
@Autowired public TennisCoach(FortuneService thefortuneService) { fortuneService = thefortuneService; }
configure the dependency injection with @Autowired Annotation
note that, Adding @Autowired Annotation, Spring will scan for a component that implements FortuneService interface. In our case, HappyFortuneService meets the requirement.
note that, If the class has only one constructor defined then the @Autowired annotation is not required as of Spring 4.3+.
setter injection
method injection -> Spring can scan the component and inject the implementation of the class into any customized method
Field Injection
@Autowired private FortuneService fortuneService; // don't need any constructor or setter method
Qualifier Annotation
should specify the name of the implementation class
@Autowired @Qualifier("happyFortuneService") // default name of the class private FortuneService fortuneService;
how to inject properties file using Java annotations
Create a properties file to hold your properties.It will be a name value pair
Load the properties file in the XML config file
eg. in the applicationContext.xml, add following lines:
- <context:property-placeholder location ="classpath:sport.properties"/>
inject the properties values into your Swim Coach:
- eg. @Value("${foo.email}") private String email;
bean scope for Annotation
by default: singlton
prototype scope: new object for each request
eg. @Component @Scope("prototype") public class TennisCoach implements Coach {...}
bean lifecycle method annotation
@PostConstruct
@PreDestroy
note that: Access modifier: The method can have any access modifier (public, protected, private);;; Return type: the method can have any return type. However, "void' is most commonly used. If you give a return type just note that you will not be able to capture the return value. As a result, "void" is commonly used. Method name: the method can have any method name. Arguments: the method can not accept any arguments. The method should be no-arg.
Java Configuration Class (modern)
Create a Java class and annotate as @Configuration
Add component scanning support: @ComponentScan (optional)
@Configuration @ComponentScan("com.luv2code.springdemo") public class SportConfig { ... }
Read Spring Java configuration class
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SportConfig.class);
Retrieve bean from Spring container
Coach theCoach = context.getBean("tennisCoach", Coach.class);
new Java class with no special annotations
Define method to expose bean
@Configuration public class SportConfig { @Bean public Coach swimCoach() { SwimCoach mySwimCoach = new SwimCoach(); return mySwimCoach; } }
note that: no component scan, and define each bean individually in this config class., this method name will be the "bean id"
Inject bean dependencies
@Configuration public class SportConfig { // define bean for our sad fortune service @Bean public FortuneService sadFortuneService() { return new SadFortuneService(); } // define bean for our swim coach and inject dependency @Bean public Coach swimCoach(FortuneService fortuneService) { return new SwimCoach(sadFortuneService()); // pass in a bean as a parameter } }
Read Spring Java configuration class
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SportConfig.class);
Retrieve bean from Spring container
Coach theCoach = context.getBean("swimCoach", Coach.class);
Inject value from property file
Create Properties File
- create Properties File inside of src/ folder
Load Properties File in Spring config
@Configuration @PropertySource("classpath:sport.properties") public class SportConfig { // define bean for our sad fortune service @Bean public FortuneService sadFortuneService() { return new SadFortuneService(); } ... }
Reference values from Properties File
public class SwimCoach implements Coach { private FortuneService fortuneService; @Value("${foo.email}") private String email; @Value("${foo.team}") private String team; public String getEmail() { return email; } public String getTeam() { return team; } ... }
test those values
public class SwimJavaConfigDemoApp { public static void main(String[] args) { ... // get the beanfrom spring container SwimCoach theCoach = context.getBean("swimCoach", SwimCoach.class); ... // call our new swim ocach methods ... has the props values injected System.out.println("email: " + theCoach.getEmail()); ... } }
note that:
1
Spring MVC
Spring MVC Front Controller
- Front Controller known as DispatcherServlet
- You will create: Model objects, View templates, Controller classes
Controller
- contains your business logic
- handle the request
- store/retrieve data
- place data in model
- send to appropriate view template
Model
- Store/retrieve data via backend systems
- place your data in the model
View Template
- Spring MVC is flexible, and supports many view templates
- most common is JSP + JSTL
Spring MVC Configuration Process
- Add configuration to file: WEB-INF/web.xml
- Configuration Spring MVC Dispatcher Servlet
- Set up URL mappings to Spring MVC Dispatcher Servlet
- Add configuration to file: WEB-INF/spring-mvc-demo-servlet.xml
- add support for spring component scanning
- add support for conversion, formatting and validation
Model: is a kind of Spring ui, which can contain key-value pair and you can use them in the jsp file