Reading Note for 轻量级JavaEE企业应用实战 (Spring Only) II

Bean Configuration Using Java - Annotation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Configuration
//Used to define a java configuration class
public class AppConfig
{
//Define Attribute Value that needs to be injected
@Value("Mike") String personName; //Define a field to config a value
//Config a Bean: Chinese
@Bean(name='Chinese')
//Used to define a method, which return item will be a bean in container
public Person person(){
Chinese p = new Chinese();
p.setAxe(stoneAxe());
p.setName(personName());
return p;
}
//Config a Bean: stoneAxe
@Bean(name="stoneAxe")
public Axe stoneAxe(){
return new StoneAxe();
}
}
//Usage: ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
//Note AppConfig is the name for Bean define class

Other Annotations

  • @Import: define a java config class. This is used to import other java config classes to current java config class
  • @Scope: Define bean’s life scope for current method
  • @Lazy: Define if current method’s bean need to be delay-initialize or not
  • @DependOn: Define a bean that needs to be initialized before current method’s bean

Make XML Load Java Config:

1
2
3
4
5
<beans....>
<context:annotation-config/>
<!-- Load Java Config -->
<bean class="org.crazyit.app.config.AppConfig"/>
</beans>

Make Java Load XML Config:

1
2
3
4
5
6
7
@Configuration
//Use ImportResource to Load XML Config
@ImportResource("classpath:/bean.xml")
public class MyConfig
{
...
}

Bean Instance Creation and Dependency Configuration

Three ways to create bean instance:

  • Use Constructor
  • Use Static Factory
  • Use Instance Factory

Use Constructor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public interface Person{
public void useAxe();
//Define a useAxe method in Person interface
}
public class Chinese implements Person{
public Axe axe;
//Default Constructor
public Chinese(){
System.out.print("Spring initialize Chinese instance");
}
//The setter method for injected value. Injected value will be a 'axe'
public void setAxe(Axe axe){
System.out.println("Spring is injecting dependency...");
this.axe = axe;
}
//Import method that defines in interface
public void useAxe(){
System.out.println(axe.chop());
}
}
public interface Axe
{
public String chop();
}
public class SteelAxe implements Axe
{
//Default Constructor
public SteelAxe(){
System.out.println("Spring initialize SteelAxe instance");
}
public String chop(){
return "Chop Method";
}
}
1
2
3
4
5
6
7
8
<beans ...>
<bean id="chinese" class="org.crazyit.app.service.impl.Chinese">
<!-- Property is used to define attributes that needs injection. Since here value is given, Chinese class must have a setAxe method. -->
<property name="axe" ref="steelAxe"/>
</bean>
<!--Define steelAxe bean -->
<bean id="steelAxe" class="org.crazyit.app.serivce.impl.SteelAxe"/>
</beans>
1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args){
ApplicationContext ctx = new ClassPathApplicationContext("bean.xml");
Person p = ctx.getBean("Chinese", Person.class);
p.useAxe();
}
/*Result of running program:
Spring initialize SteelAxe instance
Spring is injecting dependency...
Chop Method
*/

Use Static Factory:

Static factory class and factory-method needs to be defined first. Method must be static.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public interface Being{
//Define Method
public void testBeing();
}
public class Dog implements Being{
private String msg;
//setter method for inject dependency
public void setMsg(String msg){
this.msg = msg;
}
//Method to implement interface
public void testBeing(){
System.out.println(msg+ "Dog test for interface method ");
}
}
public class Cat implements Being
{
private String msg;
//public void setMsg(String msg){
this.msg = msg;
}
//Method to implement interface
public void testBeing(){
System.out.println(msg + "Cat test for interface method");
}
}
public class BeingFatory(){
/*
Get static factory method for being instance. arg decides the parameter to choose which being method
*/
public static Being getBeing(String arg){
//If parameter is dog, return dog instance
if(arg.equalsIgnoreCase("dog")){
return new Dog();
}
//Else return cat instance
else{
return new cat();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--Note both cat and dog has same class and factory-method-->
<bean id="dog" class="org.crazyit.app.factory.BeingFacory" factory-method="getBeing">
<!--Class here is the class that generate static factory, instead of the class that generate bean instance -->
<!-- Config parameter for static factory -->
<constructor-arg value="dog"/>
<!--Constructor is used to define parameter for static factory -->
<!-- Config dependency injection -->
<property name="msg" value="I'm a dog"/>
</bean>
<bean id="cat" class="org.crazyit.app.factory.BeingFacory" factory-method="getBeing">
<!-- Config parameter for static factory -->
<constructor-arg value="cat"/>
<!-- Config dependency injection -->
<property name="msg" value="I'm a cat"/>
</bean>
1
2
3
4
5
6
7
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
Being b1 = ctx.getBean("dog", Being.class); //Use dog bean
b1.testBeing();
Being b2 = ctx.getBean("cat", Being.class); //Use cat bean
b2.testBeing();
}

Use Instance Facory:

No need to add class when config bean, because Spring don’t need to instant bean anymore, Spring just use the method that can inistant bean.

Bean configuration for instance factory needs to have two attributes:

  • factory-bean: Bean id for factory bean
  • factory-method: Define method for instance factory
1
2
3
4
5
6
7
8
9
10
<!--Java class is the same as example above-->
<bean id="beingFactory" class="org.crazyit.app.factory.PersonFactory"/>
<bean id="cat" factory-bean="BeingFactory" factory-method="getBeing">
<constructor-arg value="cat">
<!--Here factory class and factory method is defined. Add constructor argument for parameter-->
</bean>
<bean id="dog" factory-bean="BeingFactory" factory-method="getBeing">
<constructor-arg value="dog"/>
</bean>

Abstract Bean

Abstract bean will not be initialized. Abstract bean always work as a parent bean that can be inheriented.

1
2
3
4
5
6
<bean id="steelAxe" class="org.carzyit.app.service.impl.SteelAxe">
<bean id="chineseTemplate" abstruct = "true">
<!--Note this bean don't have class attribute because it cannot be initialized -->
<property name="axe" ref="steelAxe"/>
</bean>
</bean>

Child Bean

If lots of beans have similar config, a bean template can be created, then child bean can inherent config info from this bean template. If child bean has different info as parent bean, child bean will overwrite parent bean config.

Following config cannot be inheriented:

  • Depends-on
  • Autowire
  • Scope
  • lazy-init
1
2
3
4
5
6
7
<bean id="chineseTemplate" class="org.crazyit.app.service.impl.Chinese" abstract="true"> <!--Either parent or child bean must define class, otherwise there will be error-->
<propery name="axe" ref="steelAxe">
</bean>
<bean id="chinese" parent="chineseTemplate">
<property name="axe" ref="stoneAxe">
<!--Since we re-assign ref again, it will replace parent bean setting-->
</bean>

Get Bean Id

User setBeanName(String name) in BeanNameAware interface:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Chinese implements BeanNameAware
{
//Keep id for this bean
private String beanName;
public void setBeanName(String name){
this.beanName = name;
}
public void info(){
System.out.println(beanName);
}
}
public void static main(String[] args){
//Create Spring Container
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
Chinese chin = ctx.getBean("chinese", Chinese.class);
chin.info();
//By calling info, we will get beanName
}

Give a bean attributes from other beans

1
2
3
4
5
6
<bean id="son2" class="org.crazyit.app.service.Son">
<property name="age">
<bean id="person.son.age" class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>
<!-- now the age attibute from person.son bean is assigned to son2 bean's age property -->
</property>
</bean>