1. 基于注解的改造
使用@Component 注解配置管理的資源
@Component("accountService")
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
}
@Component("accountDao")
public class AccountDaoImpl implements IAccountDao {
private DBAssit dbAssit;
}
當我們使用注解注入時,set 方法不用寫
建立 spring 的 xml 配置檔案并開啟對注解的支援
基于注解整合時,導入限制時需要多導入一個 context 名稱空間下的限制。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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="org.woster"></context:component-scan>
<!-- 配置 dbAssit -->
<bean id="dbAssit" class="org.woster.dbassit.DBAssit">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置資料源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///test"></property>
<property name="user" value="root"></property>
<property name="password" value="1234"></property>
</bean>
</beans>
2. 常用注解
2.1 用于建立對象的
@Component
- 作用:把資源讓 spring 來管理。相當于在 xml 中配置一個 bean。
- 屬性:
- value:指定 bean 的 id。如果不指定 value 屬性,預設 bean 的 id 是目前類的類名。首字母小寫。
@Controller @Service @Repository
他們三個注解都是針對一個的衍生注解,他們的作用及屬性都是一模一樣的。
他們隻不過是提供了更加明确的語義化。
- @Controller:一般用于表現層的注解。
- @Service:一般用于業務層的注解。
- @Repository:一般用于持久層的注解。
如果注解中有且隻有一個屬性要指派時,且名稱是 value,value 在指派是可以不寫。
2.2 用于注入資料的
@Autowired
- 自動按照類型注入。當使用注解注入屬性時,set 方法可以省略。它隻能注入其他 bean 類型。當有多個類型比對時,使用要注入的對象變量名稱作為 bean 的 id,在 spring 容器查找,找到了也可以注入成功。找不到就報錯。
@Qualifier
- 在自動按照類型注入的基礎之上,再按照 Bean 的 id 注入。它在給字段注入時不能獨立使用,必須和@Autowire 一起使用;但是給方法參數注入時,可以獨立使用。
- value:指定 bean 的 id。
@Resource
- 直接按照 Bean 的 id 注入。它也隻能注入其他 bean 類型。
- name:指定 bean 的 id。
@Value
- 注入基本資料類型和 String 類型資料的
- value:用于指定值
2.3 用于改變作用範圍的
@Scope
- 指定 bean 的作用範圍。
- value:指定範圍的值。取值:singleton prototype request session globalsession
2.4 和生命周期相關的
@PostConstruct
- 用于指定初始化方法。
@PreDestroy
- 用于指定銷毀方法。
2.5 關于 Spring 注解和 XML 的選擇問題
- 注解的優勢:配置簡單,維護友善(我們找到類,就相當于找到了對應的配置)。
- XML 的優勢:修改時,不用改源碼。不涉及重新編譯和部署
基于XML配置 | 基于注解配置 | |
---|---|---|
Bean定義 | <bean id="…“ class=”…"/> | @Component 衍生類@Repository @Service @Controller |
Bean名稱 | 通過id或name 指定 | @Component(“person”) |
Bean注入 | <property>或者 通過p名命空間 | @Autowired按類型注入 @Qualifier按名稱注入 |
生命過程、 Bean作用範圍 | init-method destroy-method 範圍scope屬性 | @PostConstruct初始化 @PreDestroy銷毀 @Scope設定作用範圍 |
适合場景 | Bean來自第三 方,使用其他 | Bean的實作類由使用者自己 開發 |
基于注解的 spring IoC 配置中,bean 對象的特點和基于 XML 配置是一模一樣的。
3. spring 的純注解配置
3.1 待改造的問題
我們發現,之是以我們現在離不開 xml 配置檔案,是因為我們有一句很關鍵的配置:
<!-- 告知spring架構在,讀取配置檔案,建立容器時,掃描注解,依據注解建立對象,并存入容器中 -->
<context:component-scan base-package="org.woster"></context:component-scan>
如果他要也能用注解配置,那麼我們就離脫離 xml 檔案又進了一步。
另外,資料源和 JdbcTemplate 的配置也需要靠注解來實作。
<!-- 配置 dbAssit -->
<bean id="dbAssit" class="org.woster.dbassit.DBAssit">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置資料源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///spring_day02"></property>
<property name="user" value="root"></property>
<property name="password" value="1234"></property>
</bean>
3.2 新注解說明
@Configuration
- 用于指定目前類是一個 spring 配置類,當建立容器時會從該類上加載注解。擷取容器時需要使用AnnotationApplicationContext(有@Configuration 注解的類.class)。
- value:用于指定配置類的位元組碼
@Configuration
public class SpringConfiguration {
}
@ComponentScan
- 用于指定 spring 在初始化容器時要掃描的包。作用和在 spring 的 xml 配置檔案中的:<context:component-scan base-package=“org.woster”/>是一樣的。
- basePackages:用于指定要掃描的包。和該注解中的 value 屬性作用一樣。
@Configuration
@ComponentScan("org.woster")
public class SpringConfiguration {
}
@Bean
- 該注解隻能寫在方法上,表明使用此方法建立一個對象,并且放入 spring 容器。
- name:給目前@Bean 注解方法建立的對象指定一個名稱(即 bean 的 id)。
public class JdbcConfig {
/**
* 建立一個資料源,并存入 spring 容器中
* @return
*/
@Bean(name="dataSource")
public DataSource createDataSource() {
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setUser("root");
ds.setPassword("1234");
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql:///test");
return ds;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 建立一個 DBAssit,并且也存入 spring 容器中
* @param dataSource
* @return
*/
@Bean(name="dbAssit")
public DBAssit createDBAssit(DataSource dataSource) {
return new DBAssit(dataSource);
}
}
@PropertySource
- 用于加載.properties 檔案中的配置。例如我們配置資料源時,可以把連接配接資料庫的資訊寫到properties 配置檔案中,就可以使用此注解指定 properties 配置檔案的位置。
- value[]:用于指定 properties 檔案位置。如果是在類路徑下,需要寫上 classpath:
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 建立一個資料源,并存入 spring 容器中
* @return
*/
@Bean(name="dataSource")
public DataSource createDataSource() {
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
jdbc.properties 檔案
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=1234
@Import
- 用于導入其他配置類,在引入其他配置類時,可以不用再寫@Configuration 注解。當然,寫上也沒問題。
- value[]:用于指定其他配置類的位元組碼。
@Configuration
@ComponentScan(basePackages = "org.woster.spring")
@Import({ JdbcConfig.class})
public class SpringConfiguration {
}
@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig{
}
3.3 通過注解擷取容器
4. Spring 整合 Junit
4.1 測試類中的問題和解決思路
問題
在測試類中,每個測試方法都有以下兩行代碼:
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService as = ac.getBean("accountService",IAccountService.class);
這兩行代碼的作用是擷取容器,如果不寫的話,直接會提示空指針異常。是以又不能輕易删掉。
解決思路分析
針對上述問題,我們需要的是程式能自動幫我們建立容器。一旦程式能自動為我們建立 spring 容器,我們就無須手動建立了,問題也就解決了
我們都知道,junit 單元測試的原理(在 web 階段課程中講過),但顯然,junit 是無法實作的,因為它自己都無法知曉我們是否使用了 spring 架構,更不用說幫我們建立 spring 容器了。不過好在,junit 給我們暴露了一個注解,可以讓我們替換掉它的運作器。
這時,我們需要依靠 spring 架構,因為它提供了一個運作器,可以讀取配置檔案(或注解)來建立容器。我們隻需要告訴它配置檔案在哪就行了。
4.2 配置步驟
第一步:導入整合 junit 的必備 jar 坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
第二步:使用@RunWith 注解替換原有運作器
@RunWith(SpringJUnit4ClassRunner.class)
public class AccountServiceTest {
}
第三步:使用@ContextConfiguration 指定 spring 配置檔案的位置
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:bean.xml"})
public class AccountServiceTest {
}
@ContextConfiguration 注解:
- locations 屬性:用于指定配置檔案的位置。如果是類路徑下,需要用 classpath:表明
- classes 屬性:用于指定注解的類。當不使用 xml 配置時,需要用此屬性指定注解類的位置。
第四步:使用@Autowired 給測試類中的變量注入資料
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:bean.xml"})
public class AccountServiceTest {
@Autowired
private IAccountService as ;
}