Home - nagasudhirpulla/spring-notes GitHub Wiki

Spring Notes

JavaBrains Playlist Link

Main Concepts - Inversion of Control (IOC), Dependency Injection (DI), Event handling, Aspect Oriented Programming (AOP)

Inversion of Control (IOC)

Since the framework is creating and managing the beans for us, we have the transferred the control of managing the beans to the framework. So Inversion of Control happens by using spring framework.

By doing Dependency Injection (IOC) via spring xml and other ways, we are injecting via spring instead of us hardcoding them in our main programs. So dependency injection (DI) is also an Inversion of Control

Spring Modules Overview (Spring Architecture)

https://www.tutorialspoint.com/spring/images/spring_architecture.png

Spring IOC mechanism of creating Beans

https://www.tutorialspoint.com/spring/images/spring_ioc_container.jpg

JavaBean

  • A JavaBean is just a standard
  • All properties private (use getters/setters)
  • A public no-argument constructor
  • Implements Serializable.

Spring Bean Factory

This acts as a Factory that creates beans and manages their life cycles

An XmlBeanFactory object creates beans from spring xml. To do this create a factory and get the bean object by calling the getBean("bean_id") method

Bean xml has beans declared in it. Each bean can have a unique id attribute

Spring Application Context

It is a Spring Bean Factory with additional functionalities like AOP, event handling etc

We can create Spring Application Context from spring xml using ClassPathXmlApplicationContext object and get beans from getBean("bean_id") method

Property Initialization inside Spring Xml

Inside the spring xml, while declaring the beans, we can initialize bean properties by using the property tags inside bean tag

<bean ...>
  <property name="type" value="good"/>
</bean>

This will work only if the bean deceleration class has a setter inside it

To use constructor initialization in spring xml where the bean class has a constructor

<bean ...>
  <constructor-arg index="0" type="java.lang.String" value="abcd"/>
  <constructor-arg index="1" type="java.lang.String" value="defg"/>
</bean>

The order of class constructor arguments and the argument types can be given

Thus we have seen that we injecting properties into the beans created via Application Context through spring xml

Injecting Objects into beans and Inner Beans

Inside the bean xml if we have properties that are also beans then we can initialize them by referring to other beans or by creating inner beans inside the parent bean xml. If we create inner beans inside parent bean xml, then the inner bean need not have an id

Example of Property Initialization via reference

<bean id="triangle" class="com.sudhir.pckg.Triangle">
  <property name="pointA" ref="point1"/>
  <property name="pointB" ref="point2"/>
  <property name="pointC" ref="point3"/>
</bean>
<bean id="point1" class="com.sudhir.pckg.Point">
  <property name="x" value="25"/>
  <property name="x" value="22"/>
</bean>
<bean id="point2" class="com.sudhir.pckg.Point">
  <property name="x" value="75"/>
  <property name="x" value="52"/>
</bean>
<bean id="point3" class="com.sudhir.pckg.Point">
  <property name="x" value="84"/>
  <property name="x" value="62"/>
</bean>

Example of Property Initialization via Inner Beans

<bean id="triangle" class="com.sudhir.pckg.Triangle">
  <property name="pointA" ref="point1">
    <bean class="com.sudhir.pckg.Point">
      <property name="x" value="25"/>
      <property name="x" value="22"/>
    </bean>
  </property>
  <property name="pointB" ref="point1">
    <bean class="com.sudhir.pckg.Point">
      <property name="x" value="75"/>
      <property name="x" value="52"/>
    </bean>
  </property>
  <property name="pointC" ref="point1">
    <bean class="com.sudhir.pckg.Point">
      <property name="x" value="84"/>
      <property name="x" value="62"/>
    </bean>
  </property>
</bean>

Initializing Collections inside Beans

We can initialize properties that are List type using list tag inside the bean xml

<bean id="triangle" class="com.sudhir.pckg.Triangle">
  <property name="points" ref="point1"/>  
    <list>
      <ref bean="point1"/>
      <ref bean="point2"/>
      <ref bean="point3"/>
    </list>
  </property>
</bean>
<bean id="point1" class="com.sudhir.pckg.Point">
  <property name="x" value="25"/>
  <property name="x" value="22"/>
</bean>
<bean id="point2" class="com.sudhir.pckg.Point">
  <property name="x" value="75"/>
  <property name="x" value="52"/>
</bean>
<bean id="point3" class="com.sudhir.pckg.Point">
  <property name="x" value="84"/>
  <property name="x" value="62"/>
</bean>

Bean Aliasing

We can create an alias to a Bean using the alias tag and even give a name to a bean which will also be an alias to it. The alias can be used for referring the bean and other stuff

<bean id="triangle" class="com.sudhir.pckg.Triangle" name="triangle-name">
  ...
</bean>

<alias name="triangle" alias="triangle-alias"/>

Bean Autowiring

Autowiring can be done by name, type, constructor. Autowiring by type will work if we have a single bean for a single property declared in the xml. Autowiring by name searches for beans with same property id as the member variable names inside the parent bean and auto injects those beans into the parent bean. Autowiring by constructor is same as that of autowiring by name but it uses constructor for dependency injection.

<bean id="triangle" class="com.sudhir.pckg.Triangle" autowire="byName">  
</bean>
<bean id="pointA" class="com.sudhir.pckg.Point">
  <property name="x" value="25"/>
  <property name="x" value="22"/>
</bean>
<bean id="pointB" class="com.sudhir.pckg.Point">
  <property name="x" value="75"/>
  <property name="x" value="52"/>
</bean>
<bean id="pointC" class="com.sudhir.pckg.Point">
  <property name="x" value="84"/>
  <property name="x" value="62"/>
</bean>

Here the since the triangle class member variable names were pointA, pointB, pointC, the beans were autowired due to autowire="byName" tag

Basic Bean Scopes

The Application Context we call can be of type

  1. Singleton
  2. Prototype

For Singleton Application Context each bean is created from xml right after the creation of Application Context and the same beans are always returned for each getBean(...) call from the created spring container

For Prototype Application Context each bean is created from xml for each bean request and reference

In spring xml it is configured by the scope tag of the bean declaration

<bean id="triangle" class="com.sudhir.pckg.Triangle" scope="prototype">
  ...
</bean>

Web-Aware Context Basic Bean Scopes

The Application Context we call can be of type

  1. Request - New bean per servlet request
  2. Session - New bean per session
  3. Global Session - New bean per global http session (portlet context)

ApplicationContextAware and BeanNameAware

We can get the application context object inside the bean object by implementing the ApplicationContextAware interface

We can get the bean name of the bean name inside the bean object by implementing the BeanNameAware interface

Bean Definition Inheritance

The children beans can get the parent bean properties by default

<bean id="parentTriangle" class="com.sudhir.pckg.Triangle" abstract="true">
  <property name="pointA" ref="point1"/>
</bean>
<bean id="triangle1" class="com.sudhir.pckg.Triangle" parent="parentTriangle">
  <property name="pointB" ref="point2"/>
  <property name="pointC" ref="point3"/>
</bean>
<bean id="triangle2" class="com.sudhir.pckg.Triangle" parent="triangle1">
  <property name="pointB" ref="point2"/>
</bean>
<bean id="point1" class="com.sudhir.pckg.Point">
  ...
</bean>
<bean id="point2" class="com.sudhir.pckg.Point">
  ...
</bean>
<bean id="point3" class="com.sudhir.pckg.Point">
  ...
</bean>

If we write abstract=true then the bean cannot be created by factory but can be used as template for children

If we inherit a list from parent and merge properties in addition to the parent list the use merge="true" in the list tag

<bean id="parentTriangle" class="com.sudhir.pckg.Triangle">
  <property name="points" ref="point1"/>  
    <list>
      <ref bean="point1"/>
    </list>
  </property>
</bean>
<bean id="triangle1" class="com.sudhir.pckg.Triangle" parent="parentTriangle">
  <property name="points" ref="point1"/>  
    <list merge="true">
      <ref bean="point2"/>
      <ref bean="point2"/>
    </list>
  </property>
</bean>
<bean id="point1" class="com.sudhir.pckg.Point">
  ...
</bean>
<bean id="point2" class="com.sudhir.pckg.Point">
  ...
</bean>
<bean id="point3" class="com.sudhir.pckg.Point">
  ...
</bean>

Using AbstractApplicationContext for using Application Context life cycle callbacks

We can create an Abstract Application Context via AbstractApplicationContext class By writing context.registerShutdownHook() method, we can configure init and destroy methods on the beans by implementing InitilaizingBean and DispasableBean interfaces

We can even configure methods that are init and destroy methods inside the spring xml with the bean init-method and destroy-method bean tags

Init and destroy methods of all beans inside a bean group can be configured by the default-init-method and default-destroy-method attributes in the beans tag

<beans default-init-method="myInit" default-destroy-method="myCleanUp">
	<bean id="triangle" class="com.sudhir.pckg.Triangle" init-method="myInit" destroy-method="myCleanUp">
	  <property name="points" ref="point1"/>  
		<list>
		  <ref bean="point1"/>
		  <ref bean="point2"/>
		  <ref bean="point3"/>
		</list>
	  </property>
	</bean>
	<bean id="point1" class="com.sudhir.pckg.Point">
	  <property name="x" value="25"/>
	  <property name="x" value="22"/>
	</bean>
	<bean id="point2" class="com.sudhir.pckg.Point">
	  <property name="x" value="75"/>
	  <property name="x" value="52"/>
	</bean>
	<bean id="point3" class="com.sudhir.pckg.Point">
	  <property name="x" value="84"/>
	  <property name="x" value="62"/>
	</bean>
</beans>

Bean PostProcessor

An object implementing a BeanPostProcessor interface overrides postProcessAfterInitialization and postProcessBeforeInitialization methods that are run on every bean and the bean manipulated in the method is returned next in the pipeline

<beans default-init-method="myInit" default-destroy-method="myCleanUp">
	<bean id="triangle" class="com.sudhir.pckg.Triangle" >
	  <property name="points" ref="point1"/>  
		<list>
		  <ref bean="point1"/>
		  <ref bean="point2"/>
		  <ref bean="point3"/>
		</list>
	  </property>
	</bean>
	...
        <bean class="com.sudhir.pckg.MyBeanPostProcessor" >
        </bean>
</beans>

Bean Factory Post Processor

An object implementing a BeanFactoryPostProcessor interface overrides postProcessBeanFactory method that is run on Bean Factory

<beans default-init-method="myInit" default-destroy-method="myCleanUp">
	<bean id="triangle" class="com.sudhir.pckg.Triangle" >
	  <property name="points" ref="point1"/>  
		<list>
		  <ref bean="point1"/>
		  <ref bean="point2"/>
		  <ref bean="point3"/>
		</list>
	  </property>
	</bean>
	...
        <bean class="com.sudhir.pckg.MyBeanFactoryPP" >
        </bean>
</beans>

Assigning properties to bean properties using .properties files instead of hard coding the properties

An application of bean factory post processor is the use of PropertyPlaceHolderConfigurer that is a spring provided bean factory post processor that reads the .properties file and replaces the spring xml ${...} property values

pointsconfig.properties file

pointA.pointX = 64
pointA.pointY = 35

We are using <bean class="org.springframework.beans.factory.config.PropertyPlaceHolderConfigurer"> inside the beans tag to use the framework provided bean factory post proecessor

<beans>
	...
	<bean id="point1" class="com.sudhir.pckg.Point">
	  <property name=${pointA.pointX} value="25"/>
	  <property name=${pointA.pointY} value="22"/>
	</bean>
	...
        <bean class="org.springframework.beans.factory.config.PropertyPlaceHolderConfigurer">
          <property name="locations" value="pointsconfig.properties" />
        </bean>
</beans>

Annotations in Bean Classes

By enabling some spring post processors we can use annotations in java classes to make spring framework get some additional information about the bean

To include annotations supporting spring post processors in our application context, write <context:annotation-config/> inside the beans tag

@Required Annotation

public class Circle implements Shape{
    private Point center;
    
    @Override
    public void draw(){
        System.out.println("Drawing circle");
    }
    
    public Point getCenter(){
        return this.center;
    }
    
    @Required
    public void setCenter(Point center){
        this.center = center;
    }
}

The @Required annotation mandates the factory to create a bean with center property initialized via spring xml. Otherwise error will be thrown

@Autowired and @Qualifier Annotation

public class Circle implements Shape{
    private Point center;
    
    @Override
    public void draw(){
        System.out.println("Drawing circle");
    }
    
    public Point getCenter(){
        return this.center;
    }
    
    @Autowired
    @Qualifier("circleRelated")
    public void setCenter(Point center){
        this.center = center;
    }
}
<beans xmlns = "http://www.springframework.org/schema/beans"
	xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context = "http://www.springframework.org/schema/context"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
	<bean id="triangle" class="com.sudhir.pckg.Circle"></bean>
	<bean id="point1" class="com.sudhir.pckg.Point">
		<qualifier value="circleRelated" />
		<property name="x" value="25"/>
		<property name="x" value="22"/>
	</bean>
        <context:annotation-config/>
</beans>

The @Autowired annotation tells spring framework to autowire the property center of the bean Circle from spring xml

The @Qualifier annotation searches the bean with qualifier property to do the autowiring so that conflicts can be avoided for autowiring if beans of same type are more than one

Some JSR 250 Annotations supported by spring

JSR - Java Specification Request is a specification that many frameworks try to implement

Spring supports some JSR 250 annotations

public class Circle implements Shape{
    private Point center;
    
    @Override
    public void draw(){
        System.out.println("Drawing circle");
    }
    
    public Point getCenter(){
        return this.center;
    }
    
    @Resource(name="point1")
    public void setCenter(Point center){
        this.center = center;
    }
    
    @PostConstruct
    public void initializeCircle(){
        ...    
    }
    
    @PreDestroy
    public void destroyCircle(){
        ...    
    }
}

The @Resource annotation searches for spring xml for the property initialization. If name is not specified, then bean with same id name is used for property initialization The @PostConstruct and @PreDestroy methods are for configuring the bean life cycle methods. We need to use AbstractApplicationContext and use shutdoen hook

@Component and @Stereotype Annotations

Instead of declaring the bean in spring xml, we can use @Component annotation to declare the class as a spring bean. The drawback is that we can only have one bean for an application context unlike spring xml where we can declare multiple beans for the same class.

<beans xmlns = "http://www.springframework.org/schema/beans"
	xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context = "http://www.springframework.org/schema/context"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
	
        ...

        <context:annotation-config/>
        <context:component-scan  base-package="com.sudhir.pckg" />
</beans>

Use <context:component-scan base-package="com.sudhir.pckg" /> inside beans tag to get the component scan post processor to work

There are other Stereotypes like @Repository, @Service, @Controller that tell spring additional information about the class in addition to component tag

Using Message Source to get text from a list of .properties files

myMessages.properties file

greeting=Hello!
drawing.point=Point is ({0},{1}) 
<beans ...>

  ...

  <bean id="messageSource" class="com.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames">
      <list>
        <value>myMessages</value>
      </list>
    </property>
  </bean>
</beans>

We can use getMessage("messageName", objectListForPlaceHolders, "Default Message", locale) from the message source object to get the message text from the properties file

Event Handling in Spring

Components of Event

  1. Event Emitter
  2. Event Listener
  3. Event

We can implement application event listener by implementing the ApplicationListener class and get the event info in the onApplicationEvent method of the class

To create a custom spring event, extend the ApplicationEvent class

To publish an event from the bean class, make the bean class implement the ApplicationEventPublisherAware class and override the public void setApplicationEventPublisher (ApplicationEventPublisher publisher) to get the handle to publisher object. Using this object we can publish the event using the publisher.publishEvent(...) method

Aspect Oriented Programming (AOP)

Used to solve the Cross Cutting Concerns like transactions, logging, security etc, which are not the business aspects but are always in the logic tree of business implementation. Using AOP, we can create Spring Aspect Objects and use aspect configuration to provide aspects to specific class methods

Wrapping Aspects around methods

    ||
    \/
Aspect Code
    ||
    \/
Target Code
    ||
    \/
Aspect Code
    ||
    \/
⚠️ **GitHub.com Fallback** ⚠️