第1章使用Spring的IOC完成保存客戶的操作:
1.1案例需求
需求描述
對於CRM的系統而言,現在有很多的DAO類,比如客戶的DAO,聯繫人DAO等等。客戶提出一個需求要開發人員實現一個功能對所有的DAO的類中以save開頭的方法實現權限的校驗,需要時管理員的身份纔可以進行保存操作。
第2章IoC容器裝配Bean_基於註解配置方式
2.1Bean的定義(註冊) – 掃描機制
新建web項目:spring4_d02_c02
第一步:
導入jar包(4個核心包+2個日誌包),
導入log4j.properties,
導入applicationContext.xml
Spring XML開發和註解開發 導入jar包是相同的
第二步: 編寫Service和DAO 的註冊
xml做法 : <bean id=”customerService” class=”…” />
,用<bean>
的方式創建對象
註解做法 : spring2.5引入 @Component
註解 如果放置到類的上面,相當於在spring容器中定義<bean id=”” class=””>
創建包:com.igeek.ioc
創建類:CustomerService.java類
/**
* @Component註解放置到類上
* 相當於spring容器中定義:<bean id="customerService" class="com.igeek.ioc.CustomerService">
* 其中id屬性默認bean的名字是類名的小寫
* ——————————————————————————————————————————————————————
* @Component(value="customer")//自定義bean的名字
* 相當於spring容器中定義:<bean id="customer" class="com.igeek.ioc.CustomerService">
* ——————————————————————————————————————————————————————
*/
@Component(value="customer")
public class CustomerService {
//保存業務方法
public void save(){
System.out.println("CustomerService業務層被調用了。。。");
}
}
第三步: 配置註解開啓和註解Bean的掃描。配置的示例如下:配置applicationContext.xml
參考:
spring-framework-4.2.4.RELEASE/docs/spring-framework-reference/html/xsd-configuration.html,搜索context關鍵字即可
<?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:context="http://www.springframework.org/schema/context"
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">
<!-- 配置註解掃描
context:component-scan:專門掃描含有@Component註解的類,自動將其作爲bean
base-package:要掃描包的路徑,包含子包,com.igeek.ioc表示子包下的所有類定義註解都有效
註解掃描配置的時候,會自動開啓註解功能
-->
<context:component-scan base-package="com.igeek.ioc"/>
</beans>
引入context 名稱空間 :
【注意】Spring的所有名稱空間都需要基於Beans的名稱空間。
引入後:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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">
配置本地提示關聯,配置eclipse的XML Catalog Element:
第四步:測試:
public class SpringTest {
@Test
public void test(){
//spring容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//獲取bean
CustomerService customerService=(CustomerService) applicationContext.getBean("customer");
customerService.save();
}
}
這裏:如果拋出異常:
說明spring4缺少aop的包,需要導入
【擴展優化】:
衍生註解的問題
實際開發中,使用的是@Component三個衍生註解(“子註解”)
子註解的作用:有分層的意義(分層註解)。
Spring3.0爲我們引入了組件自動掃描機制,它可以在類路徑底下尋找標註了@Component、@Service、@Controller、@Repository註解的類,並把這些類納入進spring容器中管理。
除了@Component外,Spring提供了3個功能基本和@Component等效的註解
功能介紹
@Service用於標註業務層組件、(如Service層)
@Controller用於標註控制層組件(如struts中的action層)
@Repository用於標註數據訪問組件,(如DAO層組件)。
而@Component泛指組件,當組件不好歸類的時候,我們可以使用這個註解進行標註。
第一步:
修改CutomerService.java
//@Component(value="customer")//註釋掉
@Service(value="customer")
public class CustomerService {
//保存業務方法
public void save(){
System.out.println("CustomerService業務層被調用了。。。");
}
}
創建CustomerDao.java
//持久層
@Repository("customerDao")
public class CustomerDao {
public void save(){
System.out.println("CustomerDao層被調用了");
}
}
【拋出問題】:如果將Dao注入到Service呢?即使用Service類調用Dao類?
回顧:如果使用xml的配置,那麼可以使用setter方法進行注入
<bean id=”” class=””>
<property name=”” ref=””></property>
</bean>
讓我們接着往下學習。
Bean屬性的依賴注入
簡單數據類型依賴注入(瞭解)
Spring3.0後,提供 @Value註解,可以完成簡單數據的注入
//@Component(value="customer")
@Service(value="customer")
public class CustomerService {
//簡單類型的成員變量
@Value("Rose")//參數的值簡單類型
private String name="Jack";
//保存業務方法
public void save(){
System.out.println("CustomerService業務層被調用了。。。");
System.out.println("name:"+name);
}
}
複雜類型數據依賴注入
下面完成,將Dao類的對象注入到Service類進行使用。
註解實現屬性依賴注入,將註解加在setXxx方法上 或者 屬性定義上 !(任選其一,省代碼了)
第一種: 使用@Value 結合SpEL ---- spring3.0 後用
//@Component(value="customer")
@Service(value="customer")
public class CustomerService {
//簡單類型的成員變量
@Value("Rose")//參數的值簡單類型
private String name="Jack";
//在屬性聲明上面注入,底層自動還是生成setCustomerDao()
//第一種: 使用@Value 結合SpEL ---- spring3.0 後用
//其中customerDao表示<bean>節點id的屬性值
/**第一種: 使用@Value 結合SpEL ---- spring3.0 後用*/
//@Value(value="#{customerDao}")
private CustomerDao customerDao;
@Value(value="#{customerDao}")
public void setCustomerDao(CustomerDao customerDao) {
this.customerDao = customerDao;
}
//保存業務方法
public void save(){
System.out.println("CustomerService業務層被調用了。。。");
System.out.println("name:"+name);
customerDao.save();
}
}
第二種:使用@Autowired 結合 @Qualifier
單獨使用@Autowired ,表示按照類型注入,會到spring容器中查找CustomerDao的類型,對應,class的屬性值,如果找到,可以匹配。
//第二種:使用spring的@Autowired
@Autowired//默認按照類型注入
private CustomerDao customerDao;
使用@Autowired + @ Qualifier 表示按照名稱注入,會到spring容器中查找customerDao的名稱,對應<bean id=””>
,id的屬性值,如果找到,可以匹配。
//第二種:使用spring的@Autowired 結合 @Qualifier
@Autowired//默認按照類型注入的
@Qualifier("customerDao")//必須配合@Autowired註解使用,根據名字注入
private CustomerDao customerDao;
第三種: JSR-250標準(基於jdk) 提供註解@Resource
單獨使用@Resource註解,表示先按照名稱注入,會到spring容器中查找customerDao的名稱,對應<bean id=””>
,id的屬性值,如果找到,可以匹配。
如果沒有找到,則會按照類型注入,會到spring容器中查找CustomerDao的類型,對應<bean class=””>
,class的屬性值,如果找到,可以匹配,如果沒有找到會拋出異常。
//第三種: JSR-250標準(jdk) 提供@Resource
@Resource//默認先按照名稱進行匹配,再按照類型進行匹配
private CustomerDao customerDao;
如果@Resource註解上添加name名稱
使用@Resource註解,則按照名稱注入,會到spring容器中查找customerDao的名稱,對應<bean id=””>
,id的屬性值,如果找到,可以匹配。
如果沒有找到,拋出異常。
//第三種: JSR-250標準(jdk) 提供@Resource
@Resource(name="customerDao")//只能按照customerDao名稱進行匹配
private CustomerDao customerDao;
第四種: JSR-330標準(jdk) 提供 @Inject (麻煩點)
需要先導入 javax.inject 的 jar ,在課前資料中查找。
使用@Inject註解,則按照類型注入,
//第四種: JSR-330標準(jdk) 提供 @Inject ,配合@Named註解
@Inject//默認按照類型注入
private CustomerDao customerDao;
使用@inject和@Named註解,則按照名稱注入
//第四種: JSR-330標準(jdk) 提供 @Inject ,配合@Named註解
@Inject//默認按照類型注入
@Named("customerDao")//按照名字注入,必須配合@Inject使用
private CustomerDao customerDao;
Bean的初始化和銷燬
使用註解定義Bean的初始化和銷燬
Spring初始化bean或銷燬bean時,有時需要作一些處理工作,因此spring可以在創建和拆卸bean的時候調用bean的兩個生命週期方法。
回顧配置文件的寫法:<bean id=“foo” class=“...Foo” init-method=“setup”destory-method=“teardown”/>
註解的寫法:
(1)當bean被載入到容器的時候調用setup ,
註解方式如下:
@PostConstruct
初始化
(2)當bean從容器中刪除的時候調用teardown(scope= singleton有效)
註解方式如下:
@PreDestroy
銷燬
使用 @PostConstruct 註解, 標明初始化方法 —相當於 init-method 指定初始化方法
使用 @PreDestroy 註解, 標明銷燬方法 ----相當於 destroy-method 指定對象銷燬方法
第一步:創建類:LifeCycleBean.java,定義構造方法、初始化的方法、銷燬的方法。
//測試生命週期過程中的初始化和銷燬bean
@Component("lifeCycleBean")
public class LifeCycleBean {
public LifeCycleBean() {
System.out.println("LifeCycleBean構造器調用了");
}
//初始化後自動調用方法:方法名隨意,但也不能太隨便,一會要配置
@PostConstruct//初始化的方法
public void init(){
System.out.println("LifeCycleBean-init初始化時調用");
}
//bean銷燬時調用的方法
@PreDestroy
public void destroy(){
System.out.println("LifeCycleBean-destroy銷燬時調用");
}
}
第二步:配置文件,配置spring容器applicationContext.xml
<?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:context="http://www.springframework.org/schema/context"
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">
<!-- 配置註解掃描
context:component-scan:專門掃描含有@Component註解的類,自動將其作爲bean
base-package:要掃描包的路徑,包含子包,com.igeek.ioc表示子包下的所有類定義註解都有效
註解掃描配置的時候,會自動開啓註解功能
-->
<context:component-scan base-package="com.igeek.ioc"/>
</beans>
第三步:使用SpringTest.java完成測試
@Test
public void testLifeCycle() throws Exception{
//spring容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//單例;此時初始化的方法已經被調用
LifeCycleBean lifeCycleBean = (LifeCycleBean)applicationContext.getBean("lifeCycleBean");
//方案一:
//((ClassPathXmlApplicationContext)applicationContext).close();
//方案二:
//反射的機制調用close方法。
//接口只是引用了一個對象。對象本身有這個方法。
//目標:通過接口引用,調用對象本來的擁有的方法
//1。獲取對象具體類的某個方法:參數1方法名,參數2:方法裏面的參數類型
Method method = applicationContext.getClass().getMethod("close");
//參數1:擁有該方法的對象的名字,參數2:方法裏面的參數的值
method.invoke(applicationContext);
}
注意:如果要執行對象的銷燬方法
條件一: 單例Bean (在容器close時,單例Bean纔會執行銷燬方法 )
條件二: 必須調用容器 close 方法
Bean的作用域
通過@Scope註解,指定Bean的作用域(默認是 singleton 單例)
回顧:XML的方式<bean id=”” class=”” scope=”prototype”>
//測試生命週期過程中的初始化和銷燬bean
@Component("lifeCycleBean")
//@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Scope("prototype")//默認是單例(singleton),更改爲多例(prototype)
public class LifeCycleBean {
}
測試:
@Test
public void testLifeCycleScope() throws Exception{
//spring容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//單例;此時初始化的方法已經被調用
LifeCycleBean lifeCycleBean1 = (LifeCycleBean)applicationContext.getBean("lifeCycleBean");
LifeCycleBean lifeCycleBean2 = (LifeCycleBean)applicationContext.getBean("lifeCycleBean");
System.out.println(lifeCycleBean1);
System.out.println(lifeCycleBean2);
}
XML和註解混合配置 (重點)
一個項目中XML和註解都有(特殊年代產物)
Spring2.0 就有@Autowired註解
Spring2.5 之後纔有@Component註解
使用
XML 完成Bean定義
註解 完成Bean屬性注入
創建包:com.igeek.ioc.mixed
第一步:使用XML的方式完成Bean的定義
創建applicationContext-mixed.xml文件,定義:
<?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:context="http://www.springframework.org/schema/context"
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">
<!-- xml方式定義bean -->
<bean id="productDao" class="com.igeek.ioc.mixed.ProductDao"/>
<bean id="productService" class="com.igeek.ioc.mixed.ProductService"/>
<!-- 需要單獨開啓註解功能 -->
<context:component-scan base-package="com.igeek.ioc"></context:component-scan>
</beans>
第二步:註解完成注入
(1)創建ProductDao類
//產品的數據層
public class ProductDao {
public void save(){
System.out.println("查詢保存到數據口--數據層調用了");
}
}
(2)創建ProductService類
//產品的業務層
public class ProductService {
//注入dao
//強調:注入必須是bean注入bean
@Autowired
private ProductDao productDao;
//產品的保存
public void save(){
System.out.println("產品保存了,--業務層");
//調用dao層
productDao.save();
}
}
測試類:
public class SpringTest {
@Test
public void test(){
//spring容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-mixed.xml");
//獲取bean
ProductService productService=(ProductService) applicationContext.getBean("productService");
productService.save();
}
}
備註:這裏配置 <context:component-scan base-package="com.igeek.ioc"></context:component-scan>
才能使用 @PostConstruct @PreDestroy @Autowired @Resource等註解
<!-- 需要在spring容器中單獨開啓註解功能,掃描com.igeek.ioc包及其子包中所有類都有效,類中都可以使用註解 -->
<context:component-scan base-package="com.igeek.ioc"></context:component-scan>
2.2Spring的junit測試集成
Spring提供spring-test-4.2.4.RELEASE.jar 可以整合junit。
優勢:可以簡化測試代碼(不需要手動創建上下文,即手動創建spring容器)
使用spring和junit集成
第一步:新建項目導入junit 開發包
第二步:導入spring-test-4.2.4.RELEASE.jar
第三步: 創建包com.igeek.test,創建類SpringTest
通過@RunWith註解,使用junit整合spring
通過@ContextConfiguration註解,指定spring容器的位置
//目標:測試一下spring的bean的某些功能
@RunWith(SpringJUnit4ClassRunner.class)//junit整合spring的測試//立馬開啓了spring的註解
@ContextConfiguration(locations="classpath:applicationContext.xml")//加載核心配置文件,自動構建spring容器
public class SpringTest {
//使用註解注入要測試的bean
@Autowired
private HelloService helloService;
@Test
public void testSayHello(){
//獲取spring容器
// ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//從spring容器中獲取bean對象
// HelloService helloService=(HelloService)applicationContext.getBean("helloService");
//測試業務功能
helloService.sayHello();
}
}
上述代碼表示:在測試類運行前的初始化的時候,會自動創建ApplicationContext對象
第四步: 通過@Autowired註解,注入需要測試的對象
在這裏注意2點:
(1)將測試對象注入到測試用例中
(2)測試用例不需要配置context:annotion-config/,或者是<context:component-scan base-package=“com.igeek”/>,因爲使用測試類運行的時候,會自動啓動註解的支持。
//使用註解注入要測試的bean
@Autowired
private HelloService helloService;
第五步:調用測試方法完成測試
@Test
public void testSayHello(){
helloService.sayHello();
}
第六步:在applicationContext.xml中添加:
<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 開啓組件掃描 -->
<context:component-scan base-package="com.igeek.ioc"/>
<!-- 創建Service -->
<bean id="helloService" class="com.igeek.test.HelloService"></bean>
</beans>