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>
    • 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

results matching ""

    No results matching ""