Spring學習第二天
IOC配置
用於創建對象
基於@Component註解配置管理的資源
@Component
作用:把資源讓 spring 來管理。相當於在 xml 中配置一個 bean相當於我們在配置文件中的 < bean id="" class="">
屬性value:指定 bean 的 id。如果不指定 value 屬性,默認 bean 的 id 是當前類的類名。首字母小寫。
使用方法:
1.拷貝必備 jar 包到工程的 lib 目錄。
2.使用@Component 註解配置管理的資源
3.創建 spring 的 xml 配置文件並開啓對註解的支持
<context:component-scan base-package=“com.gzgs”></context:component-scan>
示例代碼
@Component("accoutService")
public class AccoutServiceImpl implements AccoutService {
}
基於@component衍生的三個註解
@Controller&&@Service&&@Repository
他們三個註解都是針對一個的衍生註解,他們的作用及屬性都是一模一樣的,他們只不過是提供了更加明確的語義化。
- @Controller: 一般用於表現層的註解。
- @Service: 一般用於業務層的註解。
- @Repository: 一般用於持久層的註解。
細節:如果註解中有且只有一個屬性要賦值時,且名稱是 value, value 在賦值是可以不寫, @Controller(accoutService)即可
依賴注入
用於注入數據
@Autowired
自動按照類型注入,可以使用在方法上,也可以使用在變量上,當使用註解注入屬性時, set 方法可以省略。它只能注入其他 bean 類型。當有多個類型匹配時,使用要注入的對象變量名稱作爲 bean 的 id,在 spring 容器查找,找到了也可以注入成功。找不到就報錯。
示例代碼
@Component("accoutService")
public class AccoutServiceImpl implements AccoutService {
@Autowired
private AccoutDao accoutDao;
public AccoutServiceImpl(AccoutDao accoutDao){
this.accoutDao=accoutDao;
}
public void saveMoney() {
accoutDao.saveMoney();
}
}
工作原理
@Qualifier
作用在自動按照類型注入的基礎之上,再按照 Bean 的 id 注入。它在給字段注入時不能獨立使用,必須和@Autowire 一起使用,但是給方法參數注入時,可以獨立使用。
屬性value:指定 bean 的 id。
代碼示例
@Autowired
@Qualifier("accoutDao2")
private AccoutDao accoutDao;
@Resource
作用:直接按照 Bean 的 id 注入。它也只能注入其他 bean 類型。
屬性name:指定 bean 的 id。
代碼示例:
@Resource(name = "accoutDao2")
private AccoutDao accoutDao;
@Value
前面的三個註解Autowired、Qualifier、Resource都只能用於給bean對象賦值,不能用於給基本數據類型和String類型賦值,要給基本數據類型和String賦值的話需要用@Value這個註解。
作用:注入基本數據類型和 String 類型數據的
屬性value:用於指定值
示例代碼
@Value("333")
String string;
注意事項
1.不能作用於靜態變量(static);
2.不能作用於常量(final);
3.不能在非註冊的類中使用(類需要被註冊在spring上下文中,如用@Service,@Repository,@Component等)
4.使用這個類時,只能通過依賴注入的方式,用new的方式是不會自動注入這些配置的。
用於改變bean的作用範圍
@Scope
相當於: <bean id="" class="" scope="">
作用:指定 bean 的作用範圍。
屬性value:指定範圍的值。
取值: singleton prototype request session globalsession
代碼示例
@Scope("prototype")
public class AccountServiceImpl implements IAccountService {
用於設置生命週期的
相當於: <bean id="" class="" init-method="" destroy-method="" />
@PostConstruct
作用:用於指定初始化方法。
代碼示例
@PostConstruct
public void init(){
System.out.println("初始化方法執行了");
}
@PreDestroy
作用:用於指定銷燬方法。
代碼示例
@PreDestroy
public void destroy(){
System.out.println("銷燬方法執行了");
}
配置類的註解
@Configuration
作用:用於指定當前類是一個 spring 配置類, 當創建容器時會從該類上加載註解。 獲取容器時需要使用AnnotationApplicationContext(有@Configuration 註解的類.class)。
屬性value:用於指定配置類的字節碼
代碼示例
/**
*這是一個配置類,相當於bean.xml
*/
@Configuration
public class SpringConfiguration {
}
@ComponentScan
作用:既然用配置類來取代xml文件,那麼肯定要有一個註解能夠實現與之前在配置文件中這個標籤同樣的功能<context:component-scan base-package=“com.gzgs”/>,也就是用於指定 spring 在初始化容器時要掃描的包。
屬性basePackages:用於指定要掃描的包。和該註解中的 value 屬性作用一樣
示例代碼
@ComponentScan("com.gzgs")
public class SpringConfiguration {
}
@Bean
作用:該註解只能寫在方法上,表明使用此方法創建一個對象,並且放入 spring 容器,由於@Component只能用於類上的,以致於在使用jar包生成對象的時候不能使用這個註解,這時候就可以使用這個註解來頂替實現同樣的功能。
屬性name:給當前@Bean 註解方法創建的對象指定一個名稱(即 bean 的 id)
示例代碼
@Bean(name="runner")
@Scope("prototype")
QueryRunner createQueryRunner(@Qualifier("ds") DataSource dataSource){
new QueryRunner(dataSource);
}
@PropertySource
作用:用於加載.properties 文件中的配置。例如我們配置數據源時,可以把連接數據庫的信息寫到properties 配置文件中,就可以使用此註解指定 properties 配置文件的位置。
屬性:value[]:用於指定 properties 文件位置。如果是在類路徑下,需要寫上 classpath:
應用場景:當我們希望有寫配置不希望再代碼裏面寫死的時候,可以定義一個properties文件來保存我們的配置信息,然後使用這個註解講他們關聯起來,例如在配置數據庫連接的時候所需要的數據庫路徑以及用戶名和密碼等。
示例代碼
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {
}
@Import
作用:用於導入其他配置類,在引入其他配置類時,可以不用再寫@Configuration 註解。 當然,寫上也沒問題。
屬性:value[]:用於指定其他配置類的字節碼。
應用場景:當由於項目需要分別定義不同模塊的配置類時,可以將各個模塊的配置類導入到一個總的配置類中。
示例代碼
@Import(jdbcConfig.class)
public class SpringConfiguration {
}
通過註解獲取容器
示例代碼
ApplicationContext ac =new AnnotationConfigApplicationContext(SpringConfiguration.class);
Spring 整合 Junit
問題場景
一般的程序入口是一個main方法,但是當我們在使用@Test進行單元測試的時候,程序的運行就不走main方法了,所以我們就沒有辦法去創建IOC容器,因爲Junit無法知曉我們是否使用了 spring 框架,更不用說幫我們創建 spring 容器了。於是Junit針對了這個問題暴露一個註解,可以讓我們替換掉它的運行器。
使用方法
一、拷貝整合 junit 的必備 jar 包到 lib 目錄,可就是導入依賴,使用Maven管理工具。
二、使用@RunWith 註解替換原有運行器
示例代碼
/**
* 測試運行類
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class AccountTest {
}
三、使用@ContextConfiguration 指定 spring 配置文件的位置
示例代碼
/**
* 測試運行類
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountTest {
}
四、使用@Autowired 給測試類中的變量注入數據
示例代碼
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountTest {
@Autowired
private AccountService as;
...
}
爲什麼不把測試類配到 xml 中?
首先測試類是可以配置到xml文件中的,配置之後可以使用,但是我們還是不推薦將它配置到xml文件中,主要有兩個原因:
- 當我們在 xml 中配置了一個 bean, spring 加載配置文件創建容器時,就會創建對象。
- 測試類只是我們在測試功能時使用,而在項目中它並不參與程序邏輯,也不會有程序的邏輯或者功能上需要用到這個測試類,所以創建完了,並沒有使用。那麼存在容器中就會造成資源的浪費。
綜上所述我們不應該將一個測試類配置到xml文件中。
信息管理系統
jbbc配置類代碼
package config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
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;
@Bean(name="runner")
@Scope("prototype")
public QueryRunner createQueryRunner(@Qualifier("ds") DataSource dataSource){
return new QueryRunner(dataSource);
}
@Bean(name = "ds")
public DataSource createDataSource(){
try {
ComboPooledDataSource ds=new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
}
}
主配置類代碼
package config;
import org.springframework.context.annotation.*;
/**
* 這是一個配置類,相當於bean.xml
*/
@ComponentScan("com.gzgs")
@PropertySource("classpath:jdbcConfig.properties")
@Import(jdbcConfig.class)
public class SpringConfiguration {
}
持久層接口實現類代碼
package com.gzgs.dao.impl;
import com.gzgs.dao.AccountDao;
import com.gzgs.domain.Account;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 持久層實現類
*/
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private QueryRunner queryRunner;
public List<Account> findAll() {
try {
return queryRunner.query("select * from account", new BeanListHandler<Account>(Account.class));
}catch (Exception e){
throw new RuntimeException(e);
}
}
public Account findAccountById(int id) {
try {
return queryRunner.query("select * from account where id=?", new BeanHandler<Account>(Account.class),id);
}catch (Exception e){
throw new RuntimeException(e);
}
}
public void insertAccount(Account account) {
try {
queryRunner.update("insert into account(name,money) values(?,?)", account.getName(),account.getMoney());
}catch (Exception e){
throw new RuntimeException(e);
}
}
public void deleteAccount(int id) {
try {
queryRunner.update("delete from account where id=?",id);
}catch (Exception e){
throw new RuntimeException(e);
}
}
public void updateAccount(int id, Account account) {
try {
queryRunner.update("update account set id=?,name=?,money=?", account.getId(),account.getName(),account.getMoney(),id);
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
業務邏輯層接口實現類代碼
package com.gzgs.service.impl;
import com.gzgs.dao.AccountDao;
import com.gzgs.domain.Account;
import com.gzgs.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 業務邏輯層實現類
*/
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public List<Account> findAll() {
return accountDao.findAll();
}
public Account findAccountById(int id) {
return accountDao.findAccountById(id);
}
public void insertAccount(Account account) {
accountDao.insertAccount(account);
}
public void deleteAccount(int id) {
accountDao.deleteAccount(id);
}
public void updateAccount(int id, Account account) {
accountDao.updateAccount(id,account);
}
}
測試類代碼
package com.gzgs.test;
import com.gzgs.domain.Account;
import com.gzgs.service.AccountService;
import config.SpringConfiguration;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
/**
* 測試運行類
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountTest {
@Autowired
private AccountService as;
@Test
public void testFindAll() {
//3.執行方法
List<Account> accounts = as.findAll();
for(Account account : accounts){
System.out.println(account);
}
}
@Test
public void testFindOne() {
//3.執行方法
Account account = as.findAccountById(1);
System.out.println(account);
}
@Test
public void testSave() {
Account account = new Account();
account.setName("test anno");
account.setMoney(12345f);
//3.執行方法
as.insertAccount(account);
}
@Test
public void testUpdate() {
//3.執行方法
Account account = as.findAccountById(4);
account.setMoney(23456f);
as.updateAccount(4,account);
}
@Test
public void testDelete() {
//3.執行方法
as.deleteAccount(4);
}
}
本博客純屬個人學習筆記,學習資源來自黑馬訓練營,如有錯誤,感激指正