Spring系列之Spring經常使用註解總結

傳統的Spring作法是使用.xml文件來對bean進行注入或者是配置aop、事物,這麼作有兩個缺點:
一、若是全部的內容都配置在.xml文件中,那麼.xml文件將會十分龐大;若是按需求分開.xml文件,那麼.xml文件又會很是多。總之這將致使配置文件的可讀性與可維護性變得很低。
二、在開發中在.java文件和.xml文件之間不斷切換,是一件麻煩的事,同時這種思惟上的不連貫也會下降開發的效率。
爲了解決這兩個問題,Spring引入了註解,經過"@XXX"的方式,讓註解與Java Bean緊密結合,既大大減小了配置文件的體積,又增長了Java Bean的可讀性與內聚性。java

不使用註解:spring

先看一個不使用註解的Spring示例,在這個示例的基礎上,改爲註解版本的,這樣也能看出使用與不使用註解之間的區別,先定義一個老虎:數據庫

package com.spring.model;

public class Tiger {
    
    private String tigerName="TigerKing";
    
    public String toString(){
        return "TigerName:"+tigerName;
    }
}

 

再定義一個猴子:安全

package com.spring.model;

public class Monkey {
    
    private String monkeyName = "MonkeyKing";
    
    public String toString(){
        return "MonkeyName:" + monkeyName;
    }

}

 

定義一個動物園:app

package com.spring.model;

public class Zoo {
    private Tiger tiger;
    private Monkey monkey;
    
    public Tiger getTiger() {
        return tiger;
    }
    public void setTiger(Tiger tiger) {
        this.tiger = tiger;
    }
    public Monkey getMonkey() {
        return monkey;
    }
    public void setMonkey(Monkey monkey) {
        this.monkey = monkey;
    }
    
    public String toString(){
        return tiger + "\n" + monkey;
    }
    
}

spring的配置文件這麼寫:eclipse

<?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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    ">
    
     <bean id="zoo" class="com.spring.model.Zoo" >
        <property name="tiger" ref="tiger" />
        <property name="monkey" ref="monkey" />
    </bean>
    
    <bean id="tiger" class="com.spring.model.Tiger" />
    <bean id="monkey" class="com.spring.model.Monkey" />

</beans>

 

測試方法:異步

 

public class TestAnnotation {
    /**
     * 不使用註解
     */
    @Test
    public void test(){
        //讀取配置文件
        ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext2.xml");
        Zoo zoo=(Zoo) ctx.getBean("zoo");
        System.out.println(zoo.toString());
    }
}

 

都很熟悉,權當複習一遍了。post

一、@Autowired測試

@Autowired顧名思義,就是自動裝配,其做用是爲了消除代碼Java代碼裏面的getter/setter與bean屬性中的property。固然,getter看我的需求,若是私有屬性須要對外提供的話,應當予以保留。ui

@Autowired默認按類型匹配的方式,在容器查找匹配的Bean,當有且僅有一個匹配的Bean時,Spring將其注入@Autowired標註的變量中。

所以,引入@Autowired註解,先看一下spring配置文件怎麼寫:

 

1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans
 3     xmlns="http://www.springframework.org/schema/beans"
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5     xmlns:p="http://www.springframework.org/schema/p"
 6     xmlns:context="http://www.springframework.org/schema/context"
 7     xsi:schemaLocation="http://www.springframework.org/schema/beans
 8     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 9     http://www.springframework.org/schema/context
10     http://www.springframework.org/schema/context/spring-context-3.0.xsd
11     ">
12     
13     <context:component-scan base-package="com.spring" />
14     
15     <bean id="zoo" class="com.spring.model.Zoo" />
16     <bean id="tiger" class="com.spring.model.Tiger" />
17     <bean id="monkey" class="com.spring.model.Monkey" />
18 
19 </beans>

 

注意第13行,使用必須告訴spring一下我要使用註解了,告訴的方式有不少,<context:component-scan base-package="xxx" />是一種最簡單的,spring會自動掃描xxx路徑下的註解。

看到第15行,原來zoo裏面應當注入兩個屬性tiger、monkey,如今不須要注入了。再看下,Zoo.java也很方便,把getter/setter均可以去掉:

 

package com.spring.model;

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

public class Zoo {
    
    @Autowired
    private Tiger tiger;
    
    @Autowired
    private Monkey monkey;
    
    public String toString(){
        return tiger + "\n" + monkey;
    }
    
}

 

這裏@Autowired註解的意思就是,當Spring發現@Autowired註解時,將自動在代碼上下文中找到和其匹配(默認是類型匹配)的Bean,並自動注入到相應的地方去。

有一個細節性的問題是,假如bean裏面有兩個property,Zoo.java裏面又去掉了屬性的getter/setter並使用@Autowired註解標註這兩個屬性那會怎麼樣?答案是Spring會按照xml優先的原則去Zoo.java中尋找這兩個屬性的getter/setter,致使的結果就是初始化bean報錯。 

OK,假設此時我把.xml文件的16行、17行兩行給去掉,再運行,會拋出異常:

 

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'zoo': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.spring.model.Tiger com.spring.model.Zoo.tiger; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.spring.model.Tiger] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1074)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
    at com.spring.test.TestAnnotation.test(TestAnnotation.java:16)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.spring.model.Tiger com.spring.model.Zoo.tiger; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.spring.model.Tiger] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:502)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:282)
    ... 36 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.spring.model.Tiger] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:920)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:789)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:474)
    ... 38 more

 

由於,@Autowired註解要去尋找的是一個Bean,Tiger和Monkey的Bean定義都給去掉了,天然就不是一個Bean了,Spring容器找不到也很好理解。那麼,若是屬性找不到我不想讓Spring容器拋出異常,而就是顯示null,能夠嗎?能夠的,其實異常信息裏面也給出了提示了,就是將@Autowired註解的required屬性設置爲false便可:

 

package com.spring.model;

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

public class Zoo {
    
    @Autowired(required=false)
    private Tiger tiger;
    
    @Autowired(required=false)
    private Monkey monkey;
    
    public String toString(){
        return tiger + "\n" + monkey;
    }
    
}

 

此時,找不到tiger、monkey兩個屬性,Spring容器再也不拋出異常而是認爲這兩個屬性爲null。

二、Qualifier(指定注入Bean的名稱)

若是容器中有一個以上匹配的Bean,則能夠經過@Qualifier註解限定Bean的名稱,看下面的例子:

定義一個Car接口:

package com.spring.service;

public interface ICar {
    
    public String getCarName();
}

兩個實現類BMWCar和BenzCar:

 

package com.spring.service.impl;

import com.spring.service.ICar;

public class BMWCar implements ICar{
    
    public String getCarName(){
        return "BMW car";
    }
}

 

package com.spring.service.impl;

import com.spring.service.ICar;

public class BenzCar implements ICar{
    
    public String getCarName(){
        return "Benz car";
    }
}

 

再寫一個CarFactory,引用car(這裏先不用@Qualifier註解):

 

package com.spring.model;

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

import com.spring.service.ICar;

public class CarFactory {
    
    @Autowired
    private ICar car;
    
    public String toString(){
        return car.getCarName();
    }
    
}

 

配置文件:

 

<?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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    ">
    
    <context:component-scan base-package="com.spring" />
    
    <!-- Autowired註解配合Qualifier註解 -->
    <bean id="carFactory" class="com.spring.model.CarFactory" />
    <bean id="bmwCar" class="com.spring.service.impl.BMWCar" />
    <bean id="benz" class="com.spring.service.impl.BenzCar" />
    
</beans>

 

測試方法:

/**
 * Autowired註解配合Qualifier註解
 */
@Test
public void test1(){
    //讀取配置文件
    ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext2.xml");
    CarFactory carFactory=(CarFactory) ctx.getBean("carFactory");
    System.out.println(carFactory.toString());
}

 

運行一下,不用說,必定是報錯的,Car接口有兩個實現類,Spring並不知道應當引用哪一個實現類。

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'carFactory': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: 
Could not autowire field: private com.spring.service.ICar com.spring.model.CarFactory.car; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type [com.spring.service.ICar] is defined: expected single matching bean but found 2: [bmwCar, benz]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1074)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
    at com.spring.test.TestAnnotation.test1(TestAnnotation.java:25)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.spring.service.ICar com.spring.model.CarFactory.car; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.spring.service.ICar] is defined: expected single matching bean but found 2: [bmwCar, benz]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:502)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:282)
    ... 36 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.spring.service.ICar] is defined: expected single matching bean but found 2: [bmwCar, benz]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:796)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:474)
    ... 38 more

 

出現這種狀況一般有兩種解決辦法:
(1)、在配置文件中刪除其中一個實現類,Spring會自動去base-package下尋找Car接口的實現類,發現Car接口只有一個實現類,便會直接引用這個實現類。
(2)、實現類就是有多個該怎麼辦?此時可使用@Qualifier註解來指定Bean的名稱:

package com.spring.model;

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

import com.spring.service.ICar;

public class CarFactory {
    
    @Autowired
    @Qualifier("bmwCar")
    private ICar car;
    
    public String toString(){
        return car.getCarName();
    }
    
}

此處會注入名爲"bmwCar"的Bean。

三、Resource

@Resource註解與@Autowired註解做用很是類似,這個就簡單說了,看例子:

package com.spring.model;

import javax.annotation.Resource;

public class Zoo1 {
    
    @Resource(name="tiger")
    private Tiger tiger;
    
    @Resource(type=Monkey.class)
    private Monkey monkey;
    
    public String toString(){
        return tiger + "\n" + monkey;
    }
}

這是詳細一些的用法,說一下@Resource的裝配順序:
(1)、@Resource後面沒有任何內容,默認經過name屬性去匹配bean,找不到再按type去匹配
(2)、指定了name或者type則根據指定的類型去匹配bean
(3)、指定了name和type則根據指定的name和type去匹配bean,任何一個不匹配都將報錯

而後,區分一下@Autowired和@Resource兩個註解的區別:
(1)、@Autowired默認按照byType方式進行bean匹配,@Resource默認按照byName方式進行bean匹配
(2)、@Autowired是Spring的註解,@Resource是J2EE的註解,這個看一下導入註解的時候這兩個註解的包名就一清二楚了
Spring屬於第三方的,J2EE是Java本身的東西,所以,建議使用@Resource註解,以減小代碼和Spring之間的耦合。

四、Service

上面這個例子,還能夠繼續簡化,由於spring的配置文件裏面還有15行~17行三個bean,下一步的簡化是把這三個bean也給去掉,使得spring配置文件裏面只有一個自動掃描的標籤,加強Java代碼的內聚性並進一步減小配置文件。

要繼續簡化,可使用@Service。先看一下配置文件,固然是所有刪除了:

<?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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    ">
    
    <context:component-scan base-package="com.spring" />
    
</beans>

 

是否是感受很爽?起碼我以爲是的。OK,下面以Zoo.java爲例,其他的Monkey.java和Tiger.java都同樣:

package com.spring.model;

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

@Service
public class Zoo {
    
    @Autowired
    private Tiger tiger;
    
    @Autowired
    private Monkey monkey;
    
    public String toString(){
        return tiger + "\n" + monkey;
    }
    
}

這樣,Zoo.java在Spring容器中存在的形式就是"zoo",便可以經過ApplicationContext的getBean("zoo")方法來獲得Zoo.java。@Service註解,其實作了兩件事情:
(1)、聲明Zoo.java是一個bean,這點很重要,由於Zoo.java是一個bean,其餘的類纔可使用@Autowired將Zoo做爲一個成員變量自動注入。
(2)、Zoo.java在bean中的id是"zoo",即類名且首字母小寫。

若是,我不想用這種形式怎麼辦,就想讓Zoo.java在Spring容器中的名字叫作"Zoo",能夠的:

package com.spring.model;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

@Service("Zoo")
@Scope("prototype")
public class Zoo {
    
    @Autowired
    private Tiger tiger;
    
    @Autowired
    private Monkey monkey;
    
    public String toString(){
        return tiger + "\n" + monkey;
    }
    
}

這樣,就能夠經過ApplicationContext的getBean("Zoo")方法來獲得Zoo.java了。

這裏我還多加了一個@Scope註解,應該很好理解。由於Spring默認產生的bean是單例的,假如我不想使用單例怎麼辦,xml文件裏面能夠在bean裏面配置scope屬性。註解也是同樣,配置@Scope便可,默認是"singleton"即單例,"prototype"表示原型即每次都會new一個新的出來。

————————————————————————————————————————————————————————————————————

使用註解來構造IoC容器
用註解來向Spring容器註冊Bean。須要在applicationContext.xml中註冊<context:component-scan base-package=」pagkage1[,pagkage2,…,pagkageN]」/>。

如:在base-package指明一個包

<context:component-scan base-package="cn.gacl.java"/>

代表cn.gacl.java包及其子包中,若是某個類的頭上帶有特定的註解【@Component/@Repository/@Service/@Controller】,就會將這個對象做爲Bean註冊進Spring容器。也能夠在<context:component-scan base-package=」 」/>中指定多個包,如:

<context:component-scan base-package="cn.gacl.dao.impl,cn.gacl.service.impl,cn.gacl.action"/>

多個包逗號隔開。

一、@Component
@Component是全部受Spring 管理組件的通用形式,@Component註解能夠放在類的頭上,@Component不推薦使用。

二、@Controller
@Controller對應表現層的Bean,也就是Action,例如:

@Controller
@Scope("prototype")
public class UserAction extends BaseAction<User>{
 ……
}

使用@Controller註解標識UserAction以後,就表示要把UserAction交給Spring容器管理,Spring容器中會存在一個名字爲"userAction"action,這個名字是根據UserAction類名來取的。注意:若是@Controller不指定其value【@Controller】,則默認的bean名字爲這個類的類名首字母小寫若是指定value【@Controller(value="UserAction")】或者【@Controller("UserAction")】,則使用value做爲bean的名字

這裏的UserAction還使用了@Scope註解,@Scope("prototype")表示將Action的範圍聲明爲原型,能夠利用容器的scope="prototype"來保證每個請求有一個單獨的Action來處理,避免strutsAction的線程安全問題。spring 默認scope 是單例模式(scope="singleton"),這樣只會建立一個Action對象,每次訪問都是同一Action對象,數據不安全,struts2 是要求每次次訪問都對應不一樣的Actionscope="prototype" 能夠保證當有請求的時候都建立一個Action對象。

三、@Service
@Service對應的是業務層Bean,例如:

@Service("userService")
public class UserServiceImpl implements UserService {
………
}

 @Service("userService")註解是告訴Spring,當Spring要建立UserServiceImpl的的實例時,bean的名字必須叫作"userService",這樣當Action須要使用UserServiceImpl的的實例時,就能夠由Spring建立好的"userService",而後注入給Action:在Action只須要聲明一個名字叫"userService"的變量來接收由Spring注入的"userService"便可,具體代碼以下:

// 注入userService
@Resource(name = "userService")
private UserService userService;

注意:在Action聲明的"userService"變量的類型必須是"UserServiceImpl"或者是其父類"UserService",不然因爲類型不一致而沒法注入,因爲Action中的聲明的"userService"變量使用了@Resource註解去標註,而且指明瞭其name = "userService",這就等於告訴Spring,說我Action要實例化一個"userService",你Spring快點幫我實例化好,而後給我,當Spring看到userService變量上的@Resource的註解時,根據其指明的name屬性能夠知道,Action中須要用到一個UserServiceImpl的實例,此時Spring就會把本身建立好的名字叫作"userService"的UserServiceImpl的實例注入給Action中的"userService"變量,幫助Action完成userService的實例化,這樣在Action中就不用經過"UserService userService = new UserServiceImpl();"這種最原始的方式去實例化userService了。若是沒有Spring,那麼當Action須要使用UserServiceImpl時,必須經過"UserService userService = new UserServiceImpl();"主動去建立實例對象,但使用了Spring以後,Action要使用UserServiceImpl時,就不用主動去建立UserServiceImpl的實例了,建立UserServiceImpl實例已經交給Spring來作了,Spring把建立好的UserServiceImpl實例給Action,Action拿到就能夠直接用了。Action由原來的主動建立UserServiceImpl實例後就能夠立刻使用,變成了被動等待由Spring建立好UserServiceImpl實例以後再注入給Action,Action纔可以使用。這說明Action對"UserServiceImpl"類的「控制權」已經被「反轉」了,原來主動權在本身手上,本身要使用"UserServiceImpl"類的實例,本身主動去new一個出來立刻就可使用了,但如今本身不能主動去new "UserServiceImpl"類的實例,new "UserServiceImpl"類的實例的權力已經被Spring拿走了,只有Spring纔可以new "UserServiceImpl"類的實例,而Action只能等Spring建立好"UserServiceImpl"類的實例後,再「懇求」Spring把建立好的"UserServiceImpl"類的實例給他,這樣他纔可以使用"UserServiceImpl",這就是Spring核心思想「控制反轉」,也叫「依賴注入」,「依賴注入」也很好理解,Action須要使用UserServiceImpl幹活,那麼就是對UserServiceImpl產生了依賴,Spring把Acion須要依賴的UserServiceImpl注入(也就是「給」)給Action,這就是所謂的「依賴注入」。對Action而言,Action依賴什麼東西,就請求Spring注入給他,對Spring而言,Action須要什麼,Spring就主動注入給他。

四、@ Repository
@Repository對應數據訪問層Bean ,例如:

@Repository(value="userDao")
public class UserDaoImpl extends BaseDaoImpl<User> {
………
}

@Repository(value="userDao")註解是告訴Spring,讓Spring建立一個名字叫"userDao"的UserDaoImpl實例。

當Service須要使用Spring建立的名字叫"userDao"的UserDaoImpl實例時,就可使用@Resource(name = "userDao")註解告訴Spring,Spring把建立好的userDao注入給Service便可。

// 注入userDao,從數據庫中根據用戶Id取出指定用戶時須要用到
@Resource(name = "userDao")
private BaseDao<User> userDao;

—————————————————————————————————————————————————————————————————————

Spring經常使用註解彙總 
本文彙總了Spring的經常使用註解,以方便你們查詢和使用,具體以下:

使用註解以前要開啓自動掃描功能,其中base-package爲須要掃描的包(含子包)。

<context:component-scan base-package="cn.test"/>

@Configuration把一個類做爲一個IoC容器,它的某個方法頭上若是註冊了@Bean,就會做爲這個Spring容器中的Bean。
@Scope註解 做用域
@Lazy(true) 表示延遲初始化
@Service用於標註業務層組件、 
@Controller用於標註控制層組件(如struts中的action)
@Repository用於標註數據訪問組件,即DAO組件。
@Component泛指組件,當組件很差歸類的時候,咱們可使用這個註解進行標註。
@Scope用於指定scope做用域的(用在類上)
@PostConstruct用於指定初始化方法(用在方法上)
@PreDestory用於指定銷燬方法(用在方法上)
@DependsOn:定義Bean初始化及銷燬時的順序
@Primary:自動裝配時當出現多個Bean候選者時,被註解爲@Primary的Bean將做爲首選者,不然將拋出異常
@Autowired 默認按類型裝配,若是咱們想使用按名稱裝配,能夠結合@Qualifier註解一塊兒使用。以下:
@Autowired @Qualifier("personDaoBean") 存在多個實例配合使用
@Resource默認按名稱裝配,當找不到與名稱匹配的bean纔會按類型裝配。 @PostConstruct 初始化註解 @PreDestroy 摧毀註解 默認 單例  啓動就加載 @Async異步方法調用

相關文章
相關標籤/搜索