Suresh Rohan's Blog

This blog is all about Java, J2EE,Spring, Angular, React JS, NoSQL, Microservices, DevOps, BigData, Tutorials, Tips, Best practice, Interview questions, Views, News, Articles, Techniques, Code Samples, Reference Application and much more

Tuesday, August 6, 2013

Introducing Inversion of Control

Introducing Inversion of Control


Types of IoC


  • Dependency lookup is the more traditional approach, and at first glance, it seems more familiar to Java programmers. 
  • DI is a newer, less well established approach that, although apparently counterintuitive at first, is actually much more flexible and usable than dependency lookup.
  • With dependency-lookup–style IoC, a component must acquire a reference to a dependency
  • whereas with DI, the dependencies are literally injected into the component by the IoC container

Dependency lookup comes in two types: dependency pull  and contextualized dependency lookup (CDL).

DI also has two common flavors: constructor DI and setter DI.

Constructor DI


In constructor DI, a component’s dependencies are provided to it in its constructor(s). The component declares a constructor or a set of constructors, taking as arguments its dependencies, and the IoC container passes the dependencies to the component when it instantiates it

Component Dependency Injection Example


public class CtorDependencyInjectionDemo {
private static class DependentComponent {
private MessageService service;
private DependentComponent(MessageService service) {
Assert.notNull(service, "The 'service' argument must not be null.");
this.service = service;
}
public void run() {
this.service.execute();
}
}
public static void main(String[] args) {
BeanFactory bf = getBeanFactory();
MessageService service = (MessageService) bf.getBean("service");
DependentComponent dc = new DependentComponent(service);
dc.run();
}
private static BeanFactory getBeanFactory() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
BeanDefinitionReader reader = new PropertiesBeanDefinitionReader(bf);
reader.loadBeanDefinitions(new ClassPathResource(
"/META-INF/spring/ioc-pull-context.properties"));
return bf;
}
}



Setter DI


In setter DI, the IoC container injects a component’s dependencies into the component via JavaBeanstyle setter methods. A component’s setters expose the set of the dependencies the IoC container can manage.

Setter Dependency Injection Example

public class SetterDependencyInjectionDemo {
private static class DependentComponent {
private MessageService service;
private DependentComponent() {
}
public void setService(MessageService service) {
this.service = service;
}
public void run() {
this.service.execute();
}
}
public static void main(String[] args) {
BeanFactory bf = getBeanFactory();
MessageService service = (MessageService) bf.getBean("service");
DependentComponent dc = new DependentComponent();
dc.setService(service);
dc.run();
}
private static BeanFactory getBeanFactory() { /* code as before */ }
}


Setter DI Advantages

  • we can create an instance of the DependentComponent without having the dependency. We are free to invoke the setter at any point in the application. 
  • We can also call the setter more than once, which allows us to swap the dependency at runtime.



DI with Spring


Beans and BeanFactories

The core of Spring’s DI container is the BeanFactory. A BeanFactory is responsible for managing components and their dependencies. In Spring, the term “bean” is used to refer to any component managed by the container

you can read the BeanDefinition data from a configuration file, using either PropertiesBeanDefinitionReader or XmlBeanDefinitionReader. The two main BeanFactory implementations that come with Spring implement BeanDefinitionRegistry.

BeanFactory Implementations

DefaultListableBeanFactory -
XmlBeanFactory - The XmlBeanFactory is derived from DefaultListableBeanFactory and simply extends it to perform automatic configuration using the XmlBeanDefinitionReader

XML Bean Definition

Each bean is defined using a <bean> tag under the root of the <beans> tag. The <bean> tag typically has two attributes: id and class. The id attribute is used to give the bean its default name, and the class attribute specifies the type of the bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="oracle" class="com.apress.prospring2.ch03.di.BookwormOracle">
<property name="encyclopedia">
<bean class="com.apress.prospring2.ch03.di.HardcodedEncyclopedia"/>
</property>
</bean>
</beans>

You can see that we have defined the bean with id oracle as an instance of the BookwormOracle and that its encyclopedia property is an anonymous bean, which means that no other component can use the encyclopedia dependency of the oracle bean. If we wanted to allow other beans to use the encyclopedia bean, we would have to move it from the inner anonymous bean to a top-level bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="encyclopedia"
class="com.apress.prospring2.ch03.di.HardcodedEncyclopedia"/>
<bean id="oracle" class="com.apress.prospring2.ch03.di.BookwormOracle">
<property name="encyclopedia" ref="encyclopedia"/>
</bean>
</beans>

Using Constructor Injection

In the previous example, the Encyclopedia implementation, HardcodedEncyclopedia, contained hard-coded values for its entries. In the Spring configuration file, you can easily create a configurable Encyclopedia that allows the message to be defined externally

The ConfigurableEncyclopedia Class

public class ConfigurableEncyclopedia implements Encyclopedia {
private Map<String, Long> entries;
public ConfigurableEncyclopedia(Map<String, Long> entries) {
Assert.notNull(entries, "The 'entries' argument cannot be null.");
this.entries = entries;
}
public Long findLong(String entry) {
return this.entries.get(entry);
}
}

creating an instance of ConfigurableEncyclopedia without providing a value for the entries is impossible (and giving null will throw an IllegalArgumentException).

Creating an Instance of the ConfigurableEncyclopedia
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="encyclopedia"
class="com.apress.prospring2.ch03.di.ConfigurableEncyclopedia">
<constructor-arg>
<util:map>
<entry key="AgeOfUniverse" value="13700000000"/>
<entry key="ConstantOfLife" value="326190476"/>
</util:map>
</constructor-arg>
</bean>
<bean id="oracle" class="com.apress.prospring2.ch03.di.BookwormOracle">
<property name="encyclopedia" ref="encyclopedia"/>
</bean>
</beans>

Avoiding Constructor Confusion


public class ConstructorConfusionDemo {
private String someValue;
public ConstructorConfusionDemo(String someValue) {
System.out.println("ConstructorConfusionDemo(String) called");
this.someValue = someValue;
}
public ConstructorConfusionDemo(int someValue) {
System.out.println("ConstructorConfusionDemo(int) called");
this.someValue = "Number: " + Integer.toString(someValue);
}
public static void main(String[] args) {
BeanFactory factory = new XmlBeanFactory(
new ClassPathResource(
"/META-INF/spring/beanfactorydemo3-context.xml"));
ConstructorConfusionDemo cc =
(ConstructorConfusionDemo)factory.getBean("constructorConfusion");
System.out.println(cc);
}
public String toString() {
return someValue;
}
}

Overcoming Constructor Confusion

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="constructorConfusion"
class="com.apress.prospring2.ch03.beanfactory.ConstructorConfusionDemo">
<constructor-arg value="1" type="int"/>
</bean>
</beans>


Injection Parameters

Injecting Simple Values

To do so, simply specify the value in the configuration tag using the value attribute; alternatively. you can specify the value inside a <value> tag. By default, the value attribute and <value> tag can not only read String values but can also convert
these values to any primitive or primitive wrapper class.

public class InjectSimpleDemo {
private String name;
private int age;
private float height;
private boolean isProgrammer;
private Long ageInSeconds;
public static void main(String[] args) {
XmlBeanFactory factory = new XmlBeanFactory(
new ClassPathResource("/META-INF/spring/injectdemo1-context.xml"));
InjectSimpleDemo simple =
(InjectSimpleDemo)factory.getBean("injectSimpleDemo");
System.out.println(simple);
}
public void setAgeInSeconds(Long ageInSeconds) {
this.ageInSeconds = ageInSeconds;
}
public void setIsProgrammer(boolean isProgrammer) {
this.isProgrammer = isProgrammer;
}
public void setAge(int age) {
this.age = age;
}
public void setHeight(float height) {
this.height = height;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return String.format("Name: %s\nAge: %d\nAge in Seconds: %d\n" +
"Height: %g\nIs Programmer?: %b",
this.name, this.age, this.ageInSeconds,
this.height, this.isProgrammer);
}
}

Configuring Simple Value Injection

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="injectSimpleDemo"
class="com.apress.prospring2.ch03.beanfactory.InjectSimpleDemo">
<property name="name" value="John Smith"/>
<property name="age" value="35"/>
<property name="height" value="1.79"/>
<property name="isProgrammer" value="true"/>
<property name="ageInSeconds" value="1103760000"/>
</bean>
</beans>

Configuration Using the p Namespace

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="injectSimpleDemo"
class="com.apress.prospring2.ch03.beanfactory.InjectSimpleDemo"
p:age="35" p:ageInSeconds="1103760000"
p:height="1.79" p:isProgrammer="false"/>
</beans>


Injecting Beans in the Same Factory

you can inject one bean into another using the ref attribute; you can also
use the <ref> tag.

Configuring Bean Injection

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="encyclopedia"
class="com.apress.prospring2.ch03.di.ConfigurableEncyclopedia">
<constructor-arg>
<util:map>
<entry key="AgeOfUniverse" value="13700000000"/>
<entry key="ConstantOfLife" value="326190476"/>
</util:map>
</constructor-arg>
</bean>
<bean id="oracle" class="com.apress.prospring2.ch03.di.BookwormOracle">
<property name="encyclopedia" ref="encyclopedia"/>
</bean>
</beans>

Configuring Bean Injection Using the p Namespace


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="encyclopedia"
name="knowitall"
class="com.apress.prospring2.ch03.di.ConfigurableEncyclopedia">
<constructor-arg>
<util:map>
<entry key="AgeOfUniverse" value="13700000000"/>
<entry key="ConstantOfLife" value="326190476"/>
</util:map>
</constructor-arg>
</bean>
<bean id="oracle" class="com.apress.prospring2.ch03.di.BookwormOracle"
p:encyclopedia-ref="knowitall"/>
</beans>

Injecting Using Bean Aliases

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="encyclopedia"
name="knowitall"
class="com.apress.prospring2.ch03.di.ConfigurableEncyclopedia">
<constructor-arg>
<util:map>
<entry key="AgeOfUniverse" value="13700000000"/>
<entry key="ConstantOfLife" value="326190476"/>
</util:map>
</constructor-arg>
</bean>
<bean id="oracle" class="com.apress.prospring2.ch03.di.BookwormOracle">
<property name="encyclopedia" ref="knowitall"/>
</bean>
</beans>

Injection and BeanFactory Nesting

By allowing BeanFactories to be nested, Spring allows you to split your configuration into different files

Nesting XmlBeanFactories

XmlBeanFactory parent = new XmlBeanFactory(
new ClassPathResource("/META-INF/spring/injectdemo1-context.xml"));
XmlBeanFactory child = new XmlBeanFactory(
new ClassPathResource("/META-INF/spring/injectdemo2-context.xml"),
parent);

Inside the configuration file for the child BeanFactory, referencing a bean in the parent
BeanFactory works exactly like referencing a bean in the child BeanFactory, unless you have a bean in the child BeanFactory that shares the same name. In that case, you can no longer use the convenient ref attribute of the <property> tag but must start using the <ref parent=""/> tag.

Child BeanFactory Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="name" class="java.lang.String">
<constructor-arg value="Johnny Smith"/>
</bean>
<bean id="injectSimpleChild"
class="com.apress.prospring2.ch03.beanfactory.InjectSimpleDemo">
<property name="name" ref="name"/>
<property name="age" value="2"/>
<property name="height" value="0.8"/>
<property name="isProgrammer" value="false"/>
<property name="ageInSeconds" value="63072000"/>
</bean>

<bean id="injectSimpleChild2"
class="com.apress.prospring2.ch03.beanfactory.InjectSimpleDemo">
<property name="name">
<ref parent="name"/>
</property>
<property name="age" value="2"/>
<property name="height" value="0.8"/>
<property name="isProgrammer" value="false"/>
<property name="ageInSeconds" value="63072000"/>
</bean>
</beans>

When we run the application, the child BeanFactory has no reference to the parent
BeanFactory, and the application will fail with a BeanCreationException:

Using Collections for Injection

Collection Injection Example
public class CollectionsDemo {
private Map map;
private Properties props;
private Set set;
private List list;
public static void main(String[] args) {
BeanFactory factory = new XmlBeanFactory(
new ClassPathResource(
"/META-INF/spring/collectionsdemo1-context.xml");
CollectionsDemo instance =
(CollectionsDemo)factory.getBean("collectionsDemo");
instance.displayInfo();
}
public void setList(List list) {
this.list = list;
}
public void setSet(Set set) {
this.set = set;
}
public void setMap(Map map) {
this.map = map;
}
public void setProps(Properties props) {
this.props = props;
}
public void displayInfo() {
// display the Map
Iterator i = map.keySet().iterator();
System.out.println("Map contents:\n");
while (i.hasNext()) {
Object key = i.next();
System.out.println("Key: " + key + " - Value: " + map.get(key));
}
// display the properties
i = props.keySet().iterator();
System.out.println("\nProperties contents:\n");
while (i.hasNext()) {
String key = i.next().toString();
System.out.println("Key: " + key + " - Value: "
+ props.getProperty(key));
}
// display the set
i = set.iterator();
System.out.println("\nSet contents:\n");
while (i.hasNext()) {
System.out.println("Value: " + i.next());
}
// display the list
i = list.iterator();
System.out.println("\nList contents:\n");
while (i.hasNext()) {
System.out.println("Value: " + i.next());
}
}
}

Verbose Configuration for the CollectionsDemo

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="collectionsDemo"
class="com.apress.prospring2.ch03.beanfactory.CollectionsDemo">
<property name="map">
<map>
<entry key="someValue">
<value>Hello World!</value>
</entry>
<entry key="someBean">
<ref local="oracle"/>
</entry>
</map>
</property>
<property name="props">
<props>
<prop key="firstName">
Jan
</prop>
<prop key="secondName">
Machacek
</prop>
</props>
</property>
<property name="set">
<set>
<value>Hello World!</value>
</set>
</property>
<property name="list">
<list>
<value>Hello World!</value>
<ref local="oracle"/>
</list>
</property>
</bean>
<bean id="oracle" class="com.apress.prospring2.ch03.di.BookwormOracle"/>
</beans>

Understanding Bean Naming

<bean id="string1" class="java.lang.String"/>
<bean name="string2" class="java.lang.String"/>
<bean class="java.lang.String"/>

Bean Name Aliasing


Spring allows a bean to have more than one name, You can achieve this by specifying a comma- or semicolon-separated list of names in the name attribute of the bean’s <bean> tag.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="name1" name="name2,name3,name4" class="java.lang.String"/>
</beans>

you can use the <alias> tag, specifying one or more aliases for any given bean name

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="name1" name="name2,name3,name4" class="java.lang.String"/>
<alias name="name2" alias="namex1"/>
<alias name="name1" alias="namex2"/>
</beans>

Bean Instantiation Modes


This means that Spring maintains a single instance of the bean, all dependent objects use the same instance, and all calls to BeanFactory.getBean() return the same instance.

able to use identity comparison (==) rather than the equals() comparison to check if the beans were the same.

Nonsingleton Instantiation Modes

prototype  - Every call to the getBean() method returns a new instance of the bean.

request  -  Every call to the getBean() method in a web application will return a unique
instance of the bean for every HTTP request. This behavior is only implemented
in the WebApplicationContext and its subinterfaces.

session  - Calls to the getBean() method will return a unique instance of the bean for
every HTTP Session. Just like request, this scope is only available in
WebApplicationContext and its subinterfaces.

global session  - The getBean() calls will return a unique instance of the bean for the global HTTP session in a portlet context. Just like request and session scopes, this
instantiation mode is only supported in WebApplicationContext and its subinterfaces.

Singleton and Prototype Beans

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="singleMe" class="java.lang.String" scope="singleton">
<constructor-arg type="java.lang.String" value="Singleton -- Jan Machacek"/>
</bean>
<bean id="prototypeMe" class="java.lang.String" scope="prototype">
<constructor-arg type="java.lang.String" value="Prototype -- Jan Machacek"/>
</bean>
</beans>

Using Singletons and Prototypes

public class ScopeDemo {
private static void compare(final BeanFactory factory, final String beanName) {
String b1 = (String)factory.getBean(beanName);
String b2 = (String)factory.getBean(beanName);
System.out.println("Bean b1=" + b1 + ", b2=" + b2);
System.out.println("Same? " + (b1 == b2));
System.out.println("Equal? " + (b1.equals(b2)));
}
public static void main(String[] args) {
BeanFactory factory = new XmlBeanFactory(
new ClassPathResource(
"/META-INF/spring/beanscopedemo1-context.xml"));
compare(factory, "singleMe");
compare(factory, "prototypeMe");
}
}

output
=======
Bean b1=Singleton -- Jan Machacek, b2=Singleton -- Jan Machacek
Same? true
Equal? true
Bean b1=Prototype -- Jan Machacek, b2=Prototype -- Jan Machacek
Same? false
Equal? true

Automatically Wiring Your Beans

By default, automatic wiring is disabled. To enable it, you specify which method of automatic wiring you wish to use using the autowire attribute of the bean you wish to automatically wire.

Spring supports four modes for automatic wiring: byName, byType, constructor, and autodetect.

When using byName wiring, Spring attempts to wire each property to a bean of the same name. So, if the target bean has a property named foo and a foo bean is defined in the BeanFactory, the foo bean is assigned to the foo property of the target.

When using byType automatic wiring, Spring attempts to wire each of the properties on the target bean automatically using a bean of the same type in the BeanFactory. So if you have a property of type String on the target bean and a bean of type String in the BeanFactory, Spring wires the String bean to the target bean’s String property. If you have more than one bean of the same type, in this case String, in the same BeanFactory, Spring is unable to decide which one to use for the automatic wiring and throws an exception.

The constructor wiring mode functions just like byType wiring, except that it uses constructors rather than setters to perform the injection. Spring attempts to match the greatest numbers of arguments it can in the constructor. So, if your bean has two constructors, one that accepts a String and one that accepts a String and an Integer, and you have both a String and an Integer bean in your BeanFactory, Spring uses the two-argument constructor.

The final mode, autodetect, instructs Spring to choose between the constructor and byType modes automatically. If your bean has a default (no arguments) constructor, Spring uses byType; otherwise, it uses constructor.

BeanFactory Configuration File for the Automatic Wiring Demonstration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="foo" class="com.apress.prospring2.ch03.autowiring.Foo"/>
<bean id="bar" class="com.apress.prospring2.ch03.autowiring.Bar"/>
<bean id="byName" autowire="byName"
class="com.apress.prospring2.ch03.autowiring.Target"/>
<bean id="byType" autowire="byType"
class="com.apress.prospring2.ch03.autowiring.Target"/>
<bean id="constructor" autowire="constructor"
class="com.apress.prospring2.ch03.autowiring.Target"/>
<bean id="autodetect" autowire="autodetect"
class="com.apress.prospring2.ch03.autowiring.Target"/>
</beans>

Automatic Wiring Demonstration

public class Target {
private Foo foo;
private Foo foo2;
private Bar bar;
public Target() {
System.out.println("Target()");
}
public Target(Foo foo) {
System.out.println("Target(Foo)");
this.foo = foo;
}
public Target(Foo foo, Bar bar) {
System.out.println("Target(Foo, Bar)");
this.foo = foo;
this.bar = bar;
}
public void setDependency(Bar bar) {
System.out.println("Target.setDependency(Bar)");
this.bar = bar;
}
public void setFoo(Foo foo) {
System.out.println("Target.setFoo(Foo)");
this.foo = foo;
}
public void setFoo2(Foo foo2) {
System.out.println("Target.setFoo2(Foo)");
this.foo2 = foo2;
}
public void setBar(Bar bar) {
System.out.println("Target.setBar(Bar)");
this.bar = bar;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("Target");
sb.append("{foo=").append(foo);
sb.append(", foo2=").append(foo2);
sb.append(", bar=").append(bar);
sb.append('}');
return sb.toString();
}
}

Output
================
byName:
Target()
Target.setBar(Bar)
Target.setFoo(Foo)
Target{foo=com.apress.prospring2.ch03.autowiring.Foo, foo2=null, ➥
bar=com.apress.prospring2.ch03.autowiring.Bar}
byType:
Target()
Target.setBar(Bar)
Target.setDependency(Bar)
Target.setFoo(Foo)
Target.setFoo2(Foo)
Target{foo=com.apress.prospring2.ch03.autowiring.Foo, ➥
foo2=com.apress.prospring2.ch03.autowiring.Foo, ➥
bar=com.apress.prospring2.ch03.autowiring.Bar}
constructor:
Target(Foo, Bar)
Target{foo=com.apress.prospring2.ch03.autowiring.Foo, foo2=null, ➥
bar=com.apress.prospring2.ch03.autowiring.Bar}
autodetect:
Target()
Target.setBar(Bar)
Target.setDependency(Bar)
Target.setFoo(Foo)
Target.setFoo2(Foo)
Target{foo=com.apress.prospring2.ch03.autowiring.Foo, ➥
foo2=com.apress.prospring2.ch03.autowiring.Foo, ➥
bar=com.apress.prospring2.ch03.autowiring.Bar}
Process finished with exit code 0

Automatic Wiring Using @Autowired


public class AnnotatedTarget {
@Autowired
private Foo foo;
@Autowired
private Foo foo2;
@Autowired
private Bar bar;
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("AnnotatedTarget");
sb.append("{foo=").append(foo);
sb.append(", foo2=").append(foo2);
sb.append(", bar=").append(bar);
sb.append('}');
return sb.toString();
}
}

Checking Dependencies

Spring has three modes for dependency checking: simple, objects, and all

The simple mode checks to see whether all properties that are either collections or built-in types have values. In this mode, Spring does not check to see whether or not properties of any other types are set. This mode can be quite useful for checking whether all the configuration parameters for a bean are set, because they are typically either built-in values or collections of builtin values.

The objects mode checks any property not covered by the simple mode, but it does not check properties that are covered by simple. So if you have a bean that has two properties, one of type int and the other of type Foo, objects checks whether a value is specified for the Foo property but does not check for the int property.

The all mode checks all properties, essentially performing the checks of both the simple and objects mode

Dependency Check Target Bean

public class SimpleBean {
private int someInt;
private SimpleBean nestedSimpleBean;
public void setSomeInt(int someInt) {
this.someInt = someInt;
}
public void setNestedSimpleBean(SimpleBean nestedSimpleBean) {
this.nestedSimpleBean = nestedSimpleBean;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("SimpleBean");
sb.append("{someInt=").append(someInt);
sb.append(", nestedSimpleBean=").append(nestedSimpleBean);
sb.append('}');
return sb.toString();
}
}

Configuration File for Dependency Checking

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="target1" class="com.apress.prospring2.ch03.dependencycheck.SimpleBean"
dependency-check="simple">
<property name="someInt" value="1"/>
</bean>
<bean id="target2" class="com.apress.prospring2.ch03.dependencycheck.SimpleBean"
dependency-check="objects">
<property name="nestedSimpleBean" ref="nestedSimpleBean"/>
</bean>
<bean id="target3" class="com.apress.prospring2.ch03.dependencycheck.SimpleBean"
dependency-check="all">
<property name="nestedSimpleBean" ref="nestedSimpleBean"/>
<property name="someInt" value="1"/>
</bean>
<bean id="nestedSimpleBean"
class="com.apress.prospring2.ch03.dependencycheck.SimpleBean"/>
</beans>

Bean Inheritance

The process of keeping the shared configuration settings in sync is
quite error-prone, and on large projects, doing so can be time consuming. To get around this, Spring allows you to create a <bean> definition that inherits its property settings from another bean in the same BeanFactory. You can override the values of any properties on the child bean as required, which allows you to have full control, but the parent bean can provide each of your beans with a base configuration.

Bean Inheritance Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="parent" class="com.apress.prospring2.ch03.inheritance.SimpleBean"
abstract="true">
<property name="name" value="Jan Machacek"/>
</bean>
<bean id="bean1" class="com.apress.prospring2.ch03.inheritance.SimpleBean"
parent="parent">
<property name="age" value="28"/>
</bean>
<bean id="bean2" class="com.apress.prospring2.ch03.inheritance.SimpleBean"
parent="parent"/>
</beans>

the parent bean is declared as abstract=true, which means that Spring can’t instantiate it, but it can use it as the superbean of another bean

An example of that is in the <bean> tag for the bean1 bean. It has an extra attribute, parent, which indicates that Spring should consider the parent bean the parent of the bean. Because the bean1 bean has its own value for the age property, Spring passes this value to the bean. However, bean1 has no value for the name property, so Spring uses the value given to the parent bean. Similarly, bean2 does not include a value for the age property; therefore, it will remain at its default value ((int)0).

public class SimpleBean {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("SimpleBean");
sb.append("{name='").append(name).append('\'');
sb.append(", age=").append(age);
sb.append('}');
return sb.toString();
}
}

Output
===========>
SimpleBean{name='Jan Machacek', age=28}
SimpleBean{name='Jan Machacek', age=0}
Process finished with exit code 0

No comments:

Post a Comment