Spring的學習(2)

第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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章