基於註解配置的方式也已經逐漸代替xml。因此咱們必需要掌握使用註解的方式配置Spring。
關於實際的開發中到底使用xml仍是註解,每家公司有着不一樣的使用習慣。因此這兩種配置方式都須要掌握。
學習基於註解的IoC配置,首先得有一個認知,即註解配置和xml配置要實現的功能都是同樣的,都是要下降程序間的耦合。只是配置的形式不同。java
步驟:
1.導入jar包,相對於以前的,在基於註解的配置中,咱們還要多拷貝一個aop的jar包。spring
2.在classpath下建立一個配置文件applicationContext.xml,並導入約束,基於註解整合時,配置文件導入約束時須要多導入一個context名稱空間下的約束sql
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" 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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> </beans>
3.建立一個用於測試的類,而且加入使用@Component註解,聲明該類容許注入到Spring容器app
import org.springframework.stereotype.Component; /* * @Component 組件註解,spring在啓動的時候掃描對應的包下面的全部類型 * 若是哪個類上只要有 @Component 註解,說明這個就須要被Spring管理 * Spring在容器就建立這個類的對象 * * @Component 屬性介紹 * @Component(value="id值") * value :指定 bean 的 id值 * 能夠不寫,默認bean的id就是當前類名的 首字母小寫 * 若是寫,「value=」能夠省略,直接"id值" * */ @Component("service") public class Service { public void say() { System.out.println("你好!Spring"); } }
4.往配置文件加入掃描組件配置框架
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" 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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <!-- 配置spring要進行掃描的組件註解的包(默認包含子包)的位置 --> <context:component-scan base-package="com.gjs.service"/> </beans>
5.測試代碼ide
import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.gjs.service.Service; public class TestSpring { @Test public void testName() throws Exception { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Service service = context.getBean("service",Service.class); service.say(); } }
用於被掃描建立對象的註解,統稱爲組件註解。組件包括:@Component,@Controller,@Service,@Repository。它們的做用是標識類爲註解的組件類,啓動Spring框架的程序時,聲明將這些組件類注入到Spring容器裏面。功能相似原來配置文件的<bean>標籤。
其餘它們的功能是同樣的並無本質上的區別,哪爲何會有4個呢?
Spring初版註解的實現(spring 2.5),就是使用一個@Component。從3.0之後,做者認爲根據分層的須要,把它拆成了四個。爲了可讓開發人員,可見便可得,一看到註解,當即知道類的性質。因此分紅了四個。函數
規範:單元測試
@Controller:用於聲明表示層的組件註解
@Service:用於聲明服務層的組件註解
@Repository:用於聲明持久層的組件註解
@Component:用於聲明三層之外的組件註解
除了@Controller在SpringMVC裏面有強制的要求,SpringMVC的表示層必須使用@Controller組件註解。其餘狀況不按規範使用也不會有問題,但既然是規範就要遵照。學習
@Scope:指定做用範圍,等同於Xml配置<bean>標籤中的scope測試
@Component("service") @Scope("prototype") public class Service { public void say() { System.out.println("你好!Spring"); } }
@PostConstruct:初始化方法註解,等同於Xml配置<bean>標籤中的init-method
@PostConstruct public void init() { System.out.println("初始化方法執行了"); }
@PreDestroy:銷燬方法註解,等同於Xml配置<bean>標籤中的destroy-method
@PreDestroy public void destroy() { System.out.println("銷燬方法執行了"); }
Spring提供了兩套用註解依賴注入的解決方案
1.@Autowired +@Qualifier():是Spring定義的標籤
2.@Resouce:是J2EE的規範
@Autowired +@Qualifier()有三種注入的方式:
1.在字段上面注入
2.在方法上面注入
3.在構造方法上面注入
總體結構:
CustomeService接口:
package com.gjs.service; public interface CustomeService { public void say(); }
CustomServiceImpl1:
package com.gjs.service.impl; import org.springframework.stereotype.Service; import com.gjs.service.CustomeService; @Service("service1") public class CustomServiceImpl1 implements CustomeService { @Override public void say() { System.out.println("CustomerServiceImpl1.say()"); } }
CustomServiceImpl2:
package com.gjs.service.impl; import org.springframework.stereotype.Service; import com.gjs.service.CustomeService; @Service("service2") public class CustomServiceImpl2 implements CustomeService { @Override public void say() { System.out.println("CustomerServiceImpl2.say()"); } }
CustomController:
package com.gjs.client; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Controller; import com.gjs.service.CustomeService; @Controller("client") public class CustomController { /* * 方式一(推薦) : 在字段(成員變量)上注入 * @Autowired : * 默認會從Spring容器找對應類型的對象注入進來 * 使用@Autowired 必須保證Spring容器中最少一個類型對應bean ,若是沒有就會拋異常 * org.springframework.beans.factory.NoSuchBeanDefinitionException * 可使用 註解的 required屬性(除特殊狀況,通常不使用) * required = true/false 是不是必須有對應的對象,true 是必須有(默認),false 不是必須有 * * 若是spring容器有多個相同類型的對象,默認沒法注入也會拋異常 * org.springframework.beans.factory.NoUniqueBeanDefinitionException 不是惟一的bean異常 * 這時就須要配合使用 @Qualifier() 註解了 * @Qualifier(value="對應bean的id值")能夠在多個相同類型的對象中篩選指定惟一id的對象,「value=」能夠省略 */ //@Autowired(required=false) //@Qualifier("service1") private CustomeService customeService; /* * 方式二 :使用setter方法(屬性)注入 * 將@Autowired直接貼在set方法上面便可,程序運行,會執行set方法 * 將Spring容器對應的類型的參數賦值給 set方法的參數,類型不存在或存在多個,處理方式與方式一同樣 */ //@Autowired() //@Qualifier("service1") public void setCustomeService(CustomeService customeService) { this.customeService = customeService; } /* * 方式三 : 構造器注入 * 使用註解的IOC建立bean的狀況下 * 默認bean中有什麼樣的構造器,spring就調用那個構造器去建立對應的bean對象 * 而且會自動注入 構造器中對應類型參數的對象,無須@Autowired() * * 若是構造函數的參數類型對應的bean有多個就在 在參數前面 使用 @Qualifier()註解,指定 對應的bean的id */ public CustomController(@Qualifier("service1")CustomeService customeService) { this.customeService = customeService; } public void say() { customeService.say(); } }
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" 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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <!-- 配置spring要進行掃描的組件註解的包(默認包含子包)的位置 --> <context:component-scan base-package="com.gjs"/> </beans>
測試類TestSpring:
package com.gjs.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.gjs.client.CustomController; public class TestSpring { @Test public void testName() throws Exception { //1.讀取配置文件,建立Spring容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //獲取調用方 CustomClient對象 CustomController client = context.getBean("client", CustomController.class); //調用CustomClient對象的say()方法 client.say(); } }
@Resource 功能等同 @Autowired + @Qualifier
@Resource只能注入字段和setter方法,不能注入構造方法
CustomController類,其餘參考上面的
package com.gjs.client; import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Controller; import com.gjs.service.CustomeService; @Controller("client") public class CustomController { /* * 方式一: 字段注入 * 也是默認會從Spring容器找對應類型的對象注入進來 * 有多個相同類型時,可使用@Resource(name="對應bean的id")指定注入哪一個對象 * @Resource 必須保證須要注入的類型在Spring容器中最少有一個對象,沒有直接拋異常 */ //@Resource(name="service1") private CustomeService customeService; /* * 方式二: set方法(屬性)注入 */ @Resource(name="service1") public void setCustomeService(CustomeService customeService) { this.customeService = customeService; } public void say() { customeService.say(); } }
@Value註解:注入基本數據類型以及它們的包裝類和String類型數據的,支持${}注入Properties文件的鍵值對,等同 <proprty name=」...」 value=」${Key}」>。
@Repository public class UserDaoImpl implements UserDao { /** * @Value(value="") * 能夠從Spring容器讀取 .properties 配置文件內容 * value :配置文件的對應的key -->使用 ${key} 獲取 * 程序運行中自動將 properties 對應key的獲取出來設置給字段 * */ //等價 <property name="driverClassName" value="${jdbc.driverClassName}"> @Value("${jdbc.driverClassName}") private String driverClassName; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; //@Value("${jdbc.maxActive}") @Value("10") //開發者也手動賦值 private String maxActive; @Override public void insert(User user) { System.out.println(driverClassName); System.out.println(url); System.out.println(username); System.out.println(password); System.out.println(maxActive); } }
雖然使用註解的方式,但咱們仍是離不開xml文件,由於咱們還有配置組件掃描位置,若是這也能用註解配置,那麼咱們就能夠脫離xml文件了。
替換XML配置文件的註解:
package com.gjs.config; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import com.alibaba.druid.pool.DruidDataSource; /* * @Configuration * 說明把當前類當作成Spring框架的配置文件 * @ComponentScan * 配置註解包掃描的位置 * @PropertySource("classpath:db.properties") * 讀取.peroperties 後綴的配置文件 */ @Configuration @ComponentScan("com.gjs") @PropertySource("classpath:db.properties") public class SpringConfig { /** * @Value(value="") * 能夠從Spring容器讀取 .properties 配置文件內容 * value :配置文件的對應的key -->使用 ${key} 獲取 * 程序運行中自動將 properties 對應key的獲取出來設置給字段 * */ //等價 <property name="driverClassName" value="${jdbc.driverClassName}"> @Value("${jdbc.driverClassName}") private String driverClassName; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Value("${jdbc.maxActive}") private Integer maxActive; //<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" //init-method="init" destroy-method="close"> @Bean(name="dataSource",initMethod="init",destroyMethod="close") public DataSource getDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driverClassName); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); dataSource.setMaxActive(maxActive); return dataSource; } }
存在的問題:
1,每一個測試都要從新啓動Spring容器,啓動容器的開銷大,測試效率低下。
2,不該該是測試代碼管理Spring容器,應該是Spring容器在管理測試代碼。
Spring測試必須保證Eclipse的單元測試的最低版本是 4.12版本,若是使用的Eclipse版本很低,那麼單元測試版本可能低於4.12,那麼須要開發者手動導入單元測試的jar包
要使用Spring測試就要先導入test的jar包
package com.gjs.test; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.gjs.client.CustomController; //表示先啓動Spring容器,把junit運行在Spring容器中 @RunWith(SpringJUnit4ClassRunner.class) //表示從哪裏加載資源文件,默認從src(源目錄)下面加載 @ContextConfiguration("classpath:applicationContext.xml") public class TestSpring { @Test public void testName() throws Exception { //1.讀取配置文件,建立Spring容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //獲取調用方 CustomClient對象 CustomController client = context.getBean("client", CustomController.class); //調用CustomClient對象的say()方法 client.say(); } }