2016年8月19日 星期五

IoC - Annotation (@Autowired)

在 spring 早期版本,只能透過 xml 進行配置設定,這會讓設定與程式是分開的,當程式很大、類別很多時,維護非常不容易,現在 spring framework 提供 annotation 的方式,把設定直接寫在程式上,可大量減輕維護的工作量。這裡說明怎麼以 annotation (註釋) 的方式進行 IoC,這個簡單的例子是一家公司有老闆,也有員工,我們要印出老闆名字和員工人數,整個專案會有如下幾個檔案:


MyTest 是測試程式,內容如下:

package tw.idv.leader;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import tw.idv.leader.pojo.Company;

public class MyTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("tw/idv/leader/beans-config.xml");
        Company company = (Company) context.getBean("company");
        System.out.println("老闆名字: " + company.getBoss().getName());
        System.out.println("員工人數: " + company.getEmployee().getCount());
    }
}


現在看一下傳統 IoC 和使用 annotation IoC 的方式有什麼不一樣。

【傳統方式】

Company.java
package tw.idv.leader.pojo;

import org.springframework.beans.factory.annotation.Autowired;

public class Company {
    private Boss boss;
    private Employee employee;

    public Boss getBoss() {
        return boss;
    }

    public void setBoss(Boss boss) {
        this.boss = boss;
    }

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }
}

注意上面兩個 setter method,設定檔將使用這兩個 setter method 進行注入; 下方紅色部份即是利用這兩個 setter method 進行注入。

beans-config.xml
<?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-2.5.xsd">

    <bean id="company" class="tw.idv.leader.pojo.Company">
        <property name="boss" ref="myBoss"/>
        <property name="employee" ref="ourEmployee"></property>
    </bean>

    <bean id="myBoss" class="tw.idv.leader.pojo.Boss">
        <property name="name" value="Steven" />
    </bean>

    <bean id="ourEmployee" class="tw.idv.leader.pojo.Employee">
        <property name="count" value="10" />
    </bean>
</beans>


【annotation方式 (1)】
類別 Company 的屬性上加上 @Autowired,取消 setter method。

Company.java
package tw.idv.leader.pojo;

import org.springframework.beans.factory.annotation.Autowired;

public class Company {
    @Autowired
    private Boss boss;
    @Autowired
        private Employee employee;

    public Boss getBoss() {
        return boss;
    }

    public Employee getEmployee() {
        return employee;
    }
}

設定檔中最重要的是加上綠色部份,現在類別 Company 沒有 setter method 了,所以,也拿掉兩個 property,spring 容器啟動時,AutowiredAnnotationBeanPostProcessor 會自動掃描所有的 bean,當發現 bean  中的屬性有 @Autowired 註釋時,就會找到與其匹配的 bean,並注入到對應的地方去。
beans-config.xml
<?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-2.5.xsd">

 <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

    <bean id="company" class="tw.idv.leader.pojo.Company" />

    <bean id="myBoss" class="tw.idv.leader.pojo.Boss">
        <property name="name" value="Steven" />
    </bean>

    <bean id="ourEmployee" class="tw.idv.leader.pojo.Employee">
        <property name="count" value="10" />
    </bean>
</beans>

【annotation方式 (2)】
這是另一種 annotation 的方式,將 @Autowired 寫在 setter method。

Company.java
package tw.idv.leader.pojo;

import org.springframework.beans.factory.annotation.Autowired;

public class Company {
    private Boss boss;
        private Employee employee;

    @Autowired
    public void setBoss(Boss boss) {
        this.boss = boss;
    }

    @Autowired
    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

    public Boss getBoss() {
        return boss;
    }

    public Employee getEmployee() {
        return employee;
    }
}

【annotation方式 (3)】
還有一種,把 annotation 寫在建構子上。

Company.java
package tw.idv.leader.pojo;

import org.springframework.beans.factory.annotation.Autowired;

public class Company {
    private Boss boss;
    private Employee employee;

    @Autowired
    public Company(Boss boss, Employee employee) {
        this.boss = boss;
        this.employee = employee;
    }

    public Boss getBoss() {
        return boss;
    }

    public Employee getEmployee() {
        return employee;
    }
}


【備註】
當不能確定 spring 容器中一定擁有某個 bean 時,可以在需要自動注入該 bean 的地方,可以使用 @Autowired(required = false),這等於告訴 spring 在找不到匹配的 bean 時也不要拋出 exception,否則只要 spring 找不到匹配的 bean 就會拋出 BeanCreationException 異常訊息。

Source: https://sites.google.com/site/stevenattw/java/spring-framework/ioc---annotation-autowired

0 意見:

張貼留言