[Spring]基于注解的IoC容器配置

概述

Spring2.5 引入了注解。
于是,一個問題產(chǎn)生了:使用注解方式注入 JavaBean 是不是一定完爆 xml方式?
未必。正所謂,仁者見仁智者見智。任何事物都有其優(yōu)缺點,看你如何取舍。來看看注解的優(yōu)缺點:
優(yōu)點:大大減少了配置,并且可以使配置更加精細(xì)——類,方法,字段都可以用注解去標(biāo)記。
缺點:使用注解,不可避免產(chǎn)生了侵入式編程,也產(chǎn)生了一些問題。

  • 你需要將注解加入你的源碼并編譯它;
  • 注解往往比較分散,不易管控。

注:spring 中,先進行注解注入,然后才是xml注入,因此如果注入的目標(biāo)相同,后者會覆蓋前者。

啟動注解

Spring 默認(rèn)是不啟用注解的。如果想使用注解,需要先在xml中啟動注解。
啟動方式:在xml中加入一個標(biāo)簽,很簡單吧。

<context:annotation-config/>

注:<context:annotation-config/> 只會檢索定義它的上下文。什么意思呢?就是說,如果你
為DispatcherServlet指定了一個WebApplicationContext,那么它只在controller中查找@Autowired注解,而不會檢查其它的路徑。

Spring注解

@Required

@Required 注解只能用于修飾bean屬性的setter方法。受影響的bean屬性必須在配置時被填充在xml配置文件中,否則容器將拋出BeanInitializationException。

public class AnnotationRequired {
    private String name;
    private String sex;

    public String getName() {
        return name;
    }

    /**
     * @Required 注解用于bean屬性的setter方法并且它指示,受影響的bean屬性必須在配置時被填充在xml配置文件中,
     *           否則容器將拋出BeanInitializationException。
     */
    @Required
    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

@Autowired

@Autowired注解可用于修飾屬性、setter方法、構(gòu)造方法。

注:@Autowired注解也可用于修飾構(gòu)造方法,但如果類中只有默認(rèn)構(gòu)造方法,則沒有必要。如果有多個構(gòu)造器,至少應(yīng)該修飾一個,來告訴容器哪一個必須使用。

可以使用JSR330的注解@Inject來替代@Autowired。

范例

public class AnnotationAutowired {
    private static final Logger log = LoggerFactory.getLogger(AnnotationRequired.class);

    @Autowired
    private Apple fieldA;

    private Banana fieldB;

    private Orange fieldC;

    public Apple getFieldA() {
        return fieldA;
    }

    public void setFieldA(Apple fieldA) {
        this.fieldA = fieldA;
    }

    public Banana getFieldB() {
        return fieldB;
    }

    @Autowired
    public void setFieldB(Banana fieldB) {
        this.fieldB = fieldB;
    }

    public Orange getFieldC() {
        return fieldC;
    }

    public void setFieldC(Orange fieldC) {
        this.fieldC = fieldC;
    }

    public AnnotationAutowired() {}

    @Autowired
    public AnnotationAutowired(Orange fieldC) {
        this.fieldC = fieldC;
    }

    public static void main(String[] args) throws Exception {
        AbstractApplicationContext ctx =
                        new ClassPathXmlApplicationContext("spring/spring-annotation.xml");

        AnnotationAutowired annotationAutowired =
                        (AnnotationAutowired) ctx.getBean("annotationAutowired");
        log.debug("fieldA: {}, fieldB:{}, fieldC:{}", annotationAutowired.getFieldA().getName(),
                        annotationAutowired.getFieldB().getName(),
                        annotationAutowired.getFieldC().getName());
        ctx.close();
    }
}

xml中的配置

<!-- 測試@Autowired -->
<bean id="apple" class="org.zp.notes.spring.beans.annotation.sample.Apple"/>
<bean id="potato" class="org.zp.notes.spring.beans.annotation.sample.Banana"/>
<bean id="tomato" class="org.zp.notes.spring.beans.annotation.sample.Orange"/>
<bean id="annotationAutowired" class="org.zp.notes.spring.beans.annotation.sample.AnnotationAutowired"/>

@Qualifier

@Autowired注解中,提到了如果發(fā)現(xiàn)有多個候選的bean都符合修飾類型,Spring就會抓瞎了。

那么,如何解決這個問題。

可以通過@Qualifier指定bean名稱來鎖定真正需要的那個bean。

范例

public class AnnotationQualifier {
    private static final Logger log = LoggerFactory.getLogger(AnnotationQualifier.class);

    @Autowired
    @Qualifier("dog") /** 去除這行,會報異常 */
    Animal dog;

    Animal cat;

    public Animal getDog() {
        return dog;
    }

    public void setDog(Animal dog) {
        this.dog = dog;
    }

    public Animal getCat() {
        return cat;
    }

    @Autowired
    public void setCat(@Qualifier("cat") Animal cat) {
        this.cat = cat;
    }

    public static void main(String[] args) throws Exception {
        AbstractApplicationContext ctx =
                new ClassPathXmlApplicationContext("spring/spring-annotation.xml");

        AnnotationQualifier annotationQualifier =
                (AnnotationQualifier) ctx.getBean("annotationQualifier");

        log.debug("Dog name: {}", annotationQualifier.getDog().getName());
        log.debug("Cat name: {}", annotationQualifier.getCat().getName());
        ctx.close();
    }
}

abstract class Animal {
    public String getName() {
        return null;
    }
}

class Dog extends Animal {
    public String getName() {
        return "狗";
    }
}

class Cat extends Animal {
    public String getName() {
        return "貓";
    }
}

xml中的配置

<!-- 測試@Qualifier -->
<bean id="dog" class="org.zp.notes.spring.beans.annotation.sample.Dog"/>
<bean id="cat" class="org.zp.notes.spring.beans.annotation.sample.Cat"/>
<bean id="annotationQualifier" class="org.zp.notes.spring.beans.annotation.sample.AnnotationQualifier"/>

JSR 250注解

@Resource

Spring支持 JSP250規(guī)定的注解@Resource。這個注解根據(jù)指定的名稱來注入bean。

如果沒有為@Resource指定名稱,它會像@Autowired一樣按照類型去尋找匹配。

在Spring中,由CommonAnnotationBeanPostProcessor來處理@Resource注解。

范例

public class AnnotationResource {
    private static final Logger log = LoggerFactory.getLogger(AnnotationResource.class);

    @Resource(name = "flower")
    Plant flower;

    @Resource(name = "tree")
    Plant tree;

    public Plant getFlower() {
        return flower;
    }

    public void setFlower(Plant flower) {
        this.flower = flower;
    }

    public Plant getTree() {
        return tree;
    }

    public void setTree(Plant tree) {
        this.tree = tree;
    }

    public static void main(String[] args) throws Exception {
        AbstractApplicationContext ctx =
                        new ClassPathXmlApplicationContext("spring/spring-annotation.xml");

        AnnotationResource annotationResource =
                        (AnnotationResource) ctx.getBean("annotationResource");
        log.debug("type: {}, name: {}", annotationResource.getFlower().getClass(), annotationResource.getFlower().getName());
        log.debug("type: {}, name: {}", annotationResource.getTree().getClass(), annotationResource.getTree().getName());
        ctx.close();
    }
}

xml的配置

<!-- 測試@Resource -->
<bean id="flower" class="org.zp.notes.spring.beans.annotation.sample.Flower"/>
<bean id="tree" class="org.zp.notes.spring.beans.annotation.sample.Tree"/>
<bean id="annotationResource" class="org.zp.notes.spring.beans.annotation.sample.AnnotationResource"/>

@PostConstruct和@PreDestroy

@PostConstruct@PreDestroy是JSR 250規(guī)定的用于生命周期的注解。

從其名號就可以看出,一個是在構(gòu)造之后調(diào)用的方法,一個是銷毀之前調(diào)用的方法。

public class AnnotationPostConstructAndPreDestroy {
    private static final Logger log = LoggerFactory.getLogger(AnnotationPostConstructAndPreDestroy.class);

    @PostConstruct
    public void init() {
        log.debug("call @PostConstruct method");
    }

    @PreDestroy
    public void destroy() {
        log.debug("call @PreDestroy method");
    }
}

JSR 330注解

從Spring3.0開始,Spring支持JSR 330標(biāo)準(zhǔn)注解(依賴注入)。

注:如果要使用JSR 330注解,需要使用外部jar包。

若你使用maven管理jar包,只需要添加依賴到pom.xml即可:

<dependency>
  <groupId>javax.inject</groupId>
  <artifactId>javax.inject</artifactId>
  <version>1</version>
</dependency>

@Inject

@Inject@Autowired一樣,可以修飾屬性、setter方法、構(gòu)造方法。

范例

public class AnnotationInject {
    private static final Logger log = LoggerFactory.getLogger(AnnotationInject.class);
    @Inject
    Apple fieldA;

    Banana fieldB;

    Orange fieldC;

    public Apple getFieldA() {
        return fieldA;
    }

    public void setFieldA(Apple fieldA) {
        this.fieldA = fieldA;
    }

    public Banana getFieldB() {
        return fieldB;
    }

    @Inject
    public void setFieldB(Banana fieldB) {
        this.fieldB = fieldB;
    }

    public Orange getFieldC() {
        return fieldC;
    }

    public AnnotationInject() {}

    @Inject
    public AnnotationInject(Orange fieldC) {
        this.fieldC = fieldC;
    }

    public static void main(String[] args) throws Exception {
        AbstractApplicationContext ctx =
                        new ClassPathXmlApplicationContext("spring/spring-annotation.xml");
        AnnotationInject annotationInject = (AnnotationInject) ctx.getBean("annotationInject");

        log.debug("type: {}, name: {}", annotationInject.getFieldA().getClass(),
                        annotationInject.getFieldA().getName());

        log.debug("type: {}, name: {}", annotationInject.getFieldB().getClass(),
                        annotationInject.getFieldB().getName());

        log.debug("type: {}, name: {}", annotationInject.getFieldC().getClass(),
                        annotationInject.getFieldC().getName());

        ctx.close();
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容