Jerry's Blog

Recording what I learned everyday

View on GitHub


22 April 2019

Spring(2)----Bean Management

by Jerry Zhang

#Tip of the Day: IntellijIDEA -> Ctrl + Alt + Shift + s -> Modules -> click Mark as to change property/type of a folder/file.



Video Link

In my last Blog, we concluded that Spring manages the objects/beans for us by a container. The question is if we did not new the Object, then how can we tell Spring what is our beans? And how to tell Spring that we want to instantiate an object?

There are two ways to make this configuration we mentioned above. One is using xml configuration file, the other is using annotation. Annotation way is more popular and much easier, but I will talk about both ways because learning xml configuration can give us more understanding about what exactly happened behind annotation.

How did we create an object without Spring? At least three ways:

  1. Use a constructor, then new Bean1()
  2. Use a static factory method, Bean2Factory.getBean2()
  3. Use a instance factory method, Bean3Factory bean3Factory = new Bean3Factory();, then Bean3 bean3 = bean3Factory.getBean3();

In Spring world, it’s very similar to the above.

My project structure:

BeanInstance

Maven dependencies:

 <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

First Create an xml file in the resources folder:

<?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 class="springioc.class005.Bean1" id="bean1"/>

    <bean class="springioc.class005.Bean2Factory" factory-method="getBean2" id="bean2"/>

    <bean class="springioc.class005.Bean3Factory" id="bean3Factory"/>
    <bean class="springioc.class005.Bean3" factory-bean="bean3Factory" factory-method="getBean3" id="bean3"/>
</beans>

Secondly, create a constructor for each bean, and create factory methods:

public class Bean1 {
    public Bean1() {
        System.out.println("Bean1.Bean1");
    }
}
public class Bean2Factory {
    public static Bean2 getBean2(){
        return new Bean2();
    }
}

Finally, we can test our code:

public class Class005Test {

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

        Bean1 bean1 = context.getBean("bean1", Bean1.class);
        System.out.println("bean1 = " + bean1);

        Bean2 bean2 = context.getBean("bean2", Bean2.class);
        System.out.println("bean2 = " + bean2);

        Bean3 bean3 = context.getBean("bean3", Bean3.class);
        System.out.println("bean3 = " + bean3);
    }
}

Use Annotation to create a bean

Next, I will explain how to use annotations to get the same result.

@Configuration
@ComponentScan(value = "springioc.class013")
public class MyConfiguration {
}
@Component
public class Bean1 {

}

@Component is just an generic annotation. Usually, we use @Controller, @Service, @Repository

public class Class013Test {

    @Test
    public void test(){
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
        Bean1 bean1 = context.getBean("bean1", Bean1.class);
        System.out.println("bean1 = " + bean1);
    }
}

Next, we can start Bean/Dependency Injection using annotation

We create three classes, MyBean, AnotherBean, MyConfiguration.

Inject an Object, anotherBean

AnotherBean is an instance variable of Mybean. anotherBean1 is injected by constructor. anotherBean2 is injected by setter. anotherBean3 is injected directly.

Inject a List

stringList is injected by setter method in MyBean and a stringList method in MyConfiguration class. We can assign an Id for the bean. If there was no id, Spring gives higher priority to the corresponding type bean, String in this example, and inject all the String beans into the stringList. We can also control the order of the injected Sting in the List with @Order annotation.

Inject a Map

Similarly, if we need to inject a Map, first, register a Map bean in the configuration class. Then, put a @Autowired annotation at the injected instance variable or its setter method. Another way is creating some methods in the configuration class, and put @Bean at these methods. The returning type must be the same as the value type of the map. The key of this Map must be String, because the default id of the bean is the method name, which always is a String.

Inject primitive type

@Value at the instance variable

MyBean:

@Component
public class MyBean {

    private AnotherBean anotherBean1;
    private AnotherBean anotherBean2;

    @Autowired
    private AnotherBean anotherBean3;

    private List<String> stringList;
    private Map<String, Integer> integerMap;

    private String string;

    private ApplicationContext context;

    public ApplicationContext getContext() {
        return context;
    }

    @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    public String getString() {
        return string;
    }

    @Value("555")
    public void setString(String string) {
        this.string = string;
    }

    public Map<String, Integer> getIntegerMap() {
        return integerMap;
    }

    @Autowired
    public void setIntegerMap(Map<String, Integer> integerMap) {
        this.integerMap = integerMap;
    }

    @Autowired
    public void setAnotherBean2(AnotherBean anotherBean2) {
        this.anotherBean2 = anotherBean2;
    }

    @Autowired
    public MyBean(AnotherBean anotherBean1) {
        this.anotherBean1 = anotherBean1;
    }

    public List<String> getStringList() {
        return stringList;
    }

    @Autowired
    @Qualifier("stringList")
    public void setStringList(List<String> stringList) {
        this.stringList = stringList;
    }

    @Override
    public String toString() {
        return "MyBean{" +
                "anotherBean1=" + anotherBean1 +
                ", anotherBean2=" + anotherBean2 +
                ", anotherBean3=" + anotherBean3 +
                ", stringList=" + stringList +
                ", integerMap=" + integerMap +
                ", string='" + string + '\'' +
                ", context=" + context +
                '}';
    }
}

AnotherBean

@Component
public class AnotherBean {
}

MyConfiguration

@Configuration
@ComponentScan("springioc.class014")
public class MyConfiguration {

    @Bean("stringList")
    public List<String> stringList(){
        ArrayList<String> list = new ArrayList<>();
        list.add("111");
        list.add("222");
        return list;
    }

    @Bean
    public Map<String, Integer> integerMap(){
        Map<String, Integer> map = new HashMap<>();
        map.put("aaa", 666);
        map.put("bbb", 777);
        return map;
    }

    @Bean
    @Order(56)
    public String string1(){
        return "333";
    }

    @Bean
    @Order(28)
    public String string2(){
        return "444";
    }

    @Bean
    public Integer integer1(){
        return 333;
    }

    @Bean
    public Integer integer2(){
        return 444;
    }
}

Test:

public class Class014Test {

    @Test
    public void test(){
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
        MyBean myBean = context.getBean("myBean", MyBean.class);
        System.out.println("myBean = " + myBean);

        for (String s : myBean.getStringList()) {
            System.out.println("s = " + s);
        }

        for (Map.Entry<String, Integer> entry : myBean.getIntegerMap().entrySet()) {
            System.out.println("entry = " + entry);
        }

        AnotherBean anotherBean = myBean.getContext().getBean("anotherBean", AnotherBean.class);
        System.out.println("anotherBean = " + anotherBean);
    }
}
tags: Spring - framework, - Bean, - Java