1. Spring簡介
1. Spring的出現是爲了取代EJB(Enterprise JavaBean)的臃腫、低效、脫離現實的缺點。Spring致力於J2EE應用的各層(表現層、業務層、持久層)的解決方案,Spring是企業應用開發的“一站式”選擇。
2. 定義:Spring是分層的JavaSE/EE應用一站式的輕量級開源框架(官網: http://spring.io/ ),以Ioc(Inverse of control)控制反轉和Aop(Aspect Oriented Programming)面向切面編程爲核心。
3. 優點:
- 輕量級:針對EJB來說,使用方便。
- 一站式:spring針對各各層(表現層、業務層、持久層)提出解決方案。
- 表現層:springmvc(spring自己的mvc框架),提供和其它web框架整合方案。
- 業務層:spring基於aop(面向切面編程)思想進行事務控制。
- 持久層:spring自己提供JdbcTemplate,提供和其它持久層框架整合的方案。
4. spring核心 :Ioc(控制反轉)和aop(面向切面編程)。重點是:IOC,spring要管理各各層的bean。
5. Spring模塊組件圖:
2. Spring IOC
1. 什麼是IOC
1. 不使用ioc,代碼中創建一個對象直接操作接口實現類,並沒有面向接口開發。面向接口開發指的是調用接口的方法,只面向接口而不面向接口實現類,因爲一個接口可能有多個實現類。而沒有面向接口開發的問題就是調用接口的類和接口實現類之間存在直接耦合。比如下列代碼
//老闆向一個寫字員發出命令去做一個工作
public class Boss {
private Writer emp;//直接使用Writer類,與Boss產生強依賴關係,直接耦合
//老闆只能向寫字員發出命令,如果想要向一個祕書或其他員工發出命令則無法實現,這顯然是不合理的
public void order(){
emp=new Writer();
emp.doJob();
}
}
public class Writer{
public void doJob(){
System.out.println("do something");
}
}
面向接口開發的改進代碼:
//老闆向一個員工發出命令去做一個工作
public class Boss {
private Employee emp;//使用Employee接口,將具體實現類與Boss解耦合,這樣就大大增強了代碼的可重用性並減弱耦合度
//老闆可以向任何一個實現了Employee接口的員工類發出命令
public void order(){
emp=new Writer();
emp.doJob();
}
}
public class Writer implements Employee{
public void doJob(){
System.out.println("do something");
}
}
public interface Employee {
public void doJob();
}
2. IOC:Inverse of Control,即控制反轉。是指將原來程序中自己創建實現類對象的控制權反轉到IOC容器中。只需要通過IOC獲了對象的實例,將IOC當成一個黑盒子、工廠。對象只與工廠耦合,對象之間沒有耦合。而上面的代碼也可以改爲
//老闆向一個員工發出命令去做一個工作
public class Boss {
private Employee emp;//使用Employee接口,這樣就大大增強了代碼的可重用性並減弱耦合度
//老闆可以向任何一個實現了Employee接口的員工類發出命令,但這裏的Employee的具體實現類對象由IOC容器提供,通過IOC容器來生成所需要的對象,這樣可以將Boss類與具體員工類解耦,所有的類之間的依賴關係都由IOC容器進行管理,便於修改維護
public void order(){
emp=IOC容器.getEmp();
emp.doJob();
}
}
public class Writer implements Employee{
public void doJob(){
System.out.println("do something");
}
}
public interface Employee {
public void doJob();
}
2. Spring IOC的使用
1. 首先建立一個Maven項目,通過Maven來導入所需要的jar包,主要是spring-webmvc.jar以及其相關的依賴jar包,使用4.3.版本,另外要注意,JDK版本與Spring版本的兼容問題,Spring4.0以後的版本建議使用JDK1.8版本;其次要導入commons-logging.jar,該包是Spring所使用的JCL日誌體系jar包,只有相關接口,具體的實現類還需要導入log4j.jar。
2. 編寫Spring IOC容器的配置文件:是一個xml文件
- 引入xml文件Spring的相關標籤約束,加入的每一個Spring的相關jar包裏都會包含該jar包相關的約束文件,具體如何添加可以網上搜索相關方法,這裏給一個基本全面的標籤約束,可以直接複製粘貼使用,xsi:schemaLocation中可以修改每個版本的約束文件,比如Spring4.3版本的beans相關約束可以將http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 改爲 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
<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" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">
- 在xml文件中的beans標籤內添加bean,bean標籤內有多個屬性以及一些嵌套標籤,用於定義bean的相關操作,下面簡單定義一個bean作爲示例
//注意,一個JavaBean類的規範實現 public class UserData{ private String cn_user_id; private String cn_user_name; private String cn_user_password; public static UserData getUser(){ return new UserData("9527","9527","9527"); } public UserData(String cn_user_id, String cn_user_name, String cn_user_password) { super(); this.cn_user_id = cn_user_id; this.cn_user_name = cn_user_name; this.cn_user_password = cn_user_password; } //IOC容器中的bean必須有無參構造方法,也就是默認構造方法 public UserData() { super(); } public String getCn_user_id() { return cn_user_id; } public void setCn_user_id(String cn_user_id) { this.cn_user_id = cn_user_id; } public String getCn_user_name() { return cn_user_name; } public void setCn_user_name(String cn_user_name) { this.cn_user_name = cn_user_name; } public String getCn_user_password() { return cn_user_password; } public void setCn_user_password(String cn_user_password) { this.cn_user_password = cn_user_password; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <!-- bean標籤: 1.id/name屬性:用來標示bean的名稱,該名稱在SpringIOC容器中不允許重複,如果不指定名稱,將默認爲類路徑 2.class屬性:IOC要管理實現類的全限定路徑名,IOC將根據此路徑去實例化類對象 --> <bean id="user" class="com.cloud_note.entity.UserData"></bean> <!-- SpringIOC實例化bean的三種方法: 1.默認無參構造器 2.有參構造器 3.靜態工廠方法 --> <!-- 有參構造器方法 --> <bean id="user1" class="com.cloud_note.entity.UserData"> <!-- index指參數在參數列表的下標,從0開始 --> <constructor-arg index="0" value="9527" type="java.lang.String"></constructor-arg> <constructor-arg index="1" value="9527" type="java.lang.String"></constructor-arg> <constructor-arg index="2" value="9527" type="java.lang.String"></constructor-arg> </bean> <!-- 靜態工廠方法,通過類中的靜態工廠方法生成bean實例 --> <bean id="user2" class="com.cloud_note.entity.UserData" factory-method="getUser"> <!-- bean作用域: 1.singleton:單例模式,即在Spring容器啓動時只生成一個bean實例,在每次訪問(getBean)時都將此對象返回,Spring容器默認此方式 2.prototype:多例模式,即每次訪問(getBean)Spring容器都會返回一個新實例 3.request 4.session --> <bean id="user" class="com.cloud_note.entity.UserData" scope="singleton"></bean> <bean id="user1" class="com.cloud_note.entity.UserData" scope="prototype"></bean> </bean> </beans>
- 編寫測試代碼,測試是否能從上面配置的IOC容器中取出指定的bean對象
//測試從Spring中獲取bean實例,該測試方法需要導入junit的jar包,來使用@Test相關注解 public class TestCase1 { //測試無參構造器方法 @Test public void test1(){ //1.獲取SpringIOC容器對象 ApplicationContext app=new ClassPathXmlApplicationContext("config/applicationContext.xml"); //2.從SpringIOC中獲取對應的bean實例 UserData user=(UserData) app.getBean("user"); System.out.println("獲取成功"); } //測試有參構造器方法 @Test public void test2(){ ApplicationContext app=new ClassPathXmlApplicationContext("config/applicationContext.xml"); UserData user=(UserData) app.getBean("user1"); System.out.println(user.getCn_user_id()); } //測試靜態工廠方法 @Test public void test3(){ ApplicationContext app=new ClassPathXmlApplicationContext("config/applicationContext.xml"); UserData user=(UserData) app.getBean("user2"); System.out.println(user.getCn_user_id()); } //獲取SpringIOC容器對象的方法 @Test public void test4(){ //1.FileSystemXmlApplicationContext是通過加載文件系統路徑下的配置文件來創建一個容器實例 ApplicationContext app1=new FileSystemXmlApplicationContext("/src/main/resources/config/applicationContext.xml"); //2.ClassPathXmlApplicationContext是通過加載classpath路徑下的配置文件來創建一個容器實例 ApplicationContext app2=new ClassPathXmlApplicationContext("config/applicationContext.xml"); //3.同時加載多個配置文件,可以連續填寫多個路徑參數或傳入數組,或者通過通配符來加載 ApplicationContext app3=new ClassPathXmlApplicationContext("config/applicationContext.xml","config/applicationContext1.xml"); String[] configs=new String[]{"config/applicationContext.xml","config/applicationContext1.xml"}; ApplicationContext app4=new ClassPathXmlApplicationContext(configs); ApplicationContext app5=new ClassPathXmlApplicationContext("classpath:config/applicationContext*.xml"); }
3. 使用註解向IOC容器中添加bean:
- 首先要在Spring配置文件中開啓組件掃描
<?xml version="1.0" encoding="UTF-8"?> <!--省略xml約束--> <beans> <!-- Spring註解開發:通過註解來管理Spring的bean --> <!-- 開啓組件掃描,用以掃描指定包內帶有實例化註解的類 --> <context:component-scan base-package="package"></context:component-scan> </beans>
- 對象實例化的註解有四種,分別是:通過註解進行實例化時,必須保證類中有默認構造方法
- @Component:指定該類爲一個普通bean,默認id爲類名首字母小寫,也可指定id,如@Component("user")
- @Repository:指定該類爲一個持久層bean,默認id爲類名首字母小寫,也可指定id,如@Repository("user")
- @Service:指定該類爲一個業務層bean,默認id爲類名首字母小寫,也可指定id,如@Service("user")
- @Controller:指定該類爲一個控制層bean,默認id爲類名首字母小寫,也可指定id,如@Controller("user")
- @Scope("prototype"/"singleton"):該註解指定bean的作用域,該註解要與以上註解搭配使用,singleton表示容器中只生成一個實例,也就是單例模式,默認爲該模式;而prototype表示會生成多個實例,每訪問一次容器就創建一次
3. DI(依賴注入)
1. 即IOC容器在運行期間動態的將對象的依賴關係注入到對象的屬性中,底層原理爲:首先生成類對象,依據所依賴的屬性類型生成屬性實例,然後通過set方法來實現注入,或通過有參構造器在生成類的實例時注入所依賴的屬性實例
2. 依賴注入的實現方式有兩種:有參構造器實現注入、set方法實現注入
3. 通過配置文件配置依賴注入:有參構造器在上面的IOC介紹中已經演示
<?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"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">
<!--set方法實現注入-->
<bean id="user" class="UserData"></bean>
<bean id="book" class="Book">
<!-- property標籤:指定注入的屬性
name屬性用來指定類中需要注入的屬性名,由set方法後的字符串首字母小寫決定,即調用注入的set方法時將由set+name屬性值
來決定調用那個set方法
ref屬性表示被注入的bean的id
value屬性表示一個具體的值,用於java中的簡單類型
-->
<property name="user" ref="user"></property>
</bean>
<!-- set方法可以注入的屬性類型 -->
<bean id="queryVo" class="QueryVo">
<!-- 基本類型 -->
<property name="t1" value="vn"></property>
<property name="t2" value="1"></property>
<!-- pojo類型 -->
<property name="t3" ref="user"></property>
<!-- List類型 List<String> -->
<property name="t4">
<list>
<value>vn</value>
</list>
</property>
<!-- List類型 List<UserData> -->
<property name="t5">
<list>
<ref bean="user"/>
</list>
</property>
<!-- Map類型 -->
<property name="t6">
<map>
<entry key="1" value="vn"></entry>
</map>
</property>
<!-- Properties類型 -->
<property name="t7">
<props>
<prop key="name">vn</prop>
</props>
</property>
</bean>
</beans>
4. 通過註解進行依賴注入:
- 首先需要開啓Spring組件掃描,並且要保證注入的屬性實例的類以及被注入的類都在Spring容器中
- @Autowired:直接標記在屬性上,依據屬性類型進行注入,即依據該類型在容器中查找相同類型或基類的bean進行注入,若依據類型查找到多個bean,則會報錯,可以在要注入的bean的類前添加實例註解時指定bean的id即可避免,也可以寫在set方法上, @Autowired會依據set方法中的參數類型來查找bean
- @Qualifier("id"):該註解要寫在@Autowired之後,搭配使用,用來指定要注入的bean的id,也可以避免上面的錯誤, 這兩個註解也可以寫在set方法上
- @Resource(name="user"):相當於@Autowired+@Qualifier(""),直接依據id查找,@Autowired是由Spring提供的,而@Resource是由jdk提供的
@Component("book")
@Scope("prototype")
public class Book implements Serializable {
private String cn_notebook_id;
//@Autowired
//@Qualifier("user")
@Resource(name="user")
private UserData user;
public UserData getUser() {
return user;
}
//@Autowired
//@Qualifier("user")
public void setUser(UserData user) {
this.user = user;
}
public String getCn_notebook_id() {
return cn_notebook_id;
}
public void setCn_notebook_id(String cn_notebook_id) {
this.cn_notebook_id = cn_notebook_id;
}
}