Spring 框架入門
一、Spring概述
什么是Spring?
??Spring是一個開源框架,Spring是于2003年興起的一個輕量級的Java開發框架,由Rod Johnson在其著作Expert One-On-One J2EE Development and Design中闡述的部分理念和原型衍生而來。
??它是為了解決企業應用開發的復雜性而創建的。框架的主要優勢之一就是其分層架構,分層架構允許使用者選擇使用哪一個組件,同時為J2EE應用程序開發提供集成的框架。
??Spring使用基本的JavaBean來完成以前只可能由EJB完成的事情。然而,Spring的用途不僅限于服務器端的開發。從簡單性、可測試性和松耦合的角度而言,任何Java應用都可以從Spring中受益。
??Spring的核心是控制反轉(IoC)和面向切面(AOP)。簡單來說,Spring是一個分層的JavaSE/EEfull-stack(一站式)輕量級開源框架。
為什么說Spring是一個一站式的輕量級開源框架呢?EE開發可分成三層架構,針對JavaEE的三層結構,每一層Spring都提供了不同的解決技術。
- WEB層:SpringMVC
- 業務層:Spring的IoC
- 持久層:Spring的JDBCTemplate(Spring的JDBC模板,ORM模板用于整合其他的持久層框架)
輕量級與重量級概念的劃分
經常會有人問到Spring是屬于輕量級框架,還是屬于重量級框架呢?其實劃分一個應用是否屬于輕量級還是重量級,主要看它使用了多少服務。使用的服務越多,容器要為普通java對象做的工作就越多,必然會影響到應用的發布時間或者是運行性能。
對于Spring容器來說,它提供了很多服務,但這些服務并不是默認為應用打開的,應用需要某種服務,還需要指明使用該服務,如果應用使用的服務很少,如:只使用了Spring核心服務,那么我們可以認為此時應用屬于輕量級的,如果應用使用了Spring提供的大部分服務,這時應用就屬于重量級的。目前EJB容器就因為它默認為應用提供了EJB規范中所有的功能,所以它屬于重量級。
Spring的核心有兩部分:
IoC:控制反轉。
舉例來說,在之前的操作中,比方說有一個類,我們想要調用類里面的方法(不是靜態方法),就要創建類的對象,使用對象調用方法實現。對于Spring來說,Spring創建對象的過程,不是在代碼里面實現的,而是交給Spring來進行配置實現的。AOP:面向切面編程。
之前,講Struts2框架的攔截器時,我們就已稍微講了一下,在Spring學習過程中,我們會著重來講它。但是本文并不會過多闡述它,下文再講。
二、為何要使用Spring
- 方便解耦,簡化開發,降低組件之間的耦合度,實現軟件各層之間的解耦。。
Spring就是一個大工廠,可以將所有對象的創建和依賴關系的維護,交給Spring管理。 - AOP編程的支持
Spring提供面向切面編程,可以方便的實現對程序進行權限攔截、運行監控等功能。 - 聲明式事務的支持
只需要通過配置就可以完成對事務的管理,而無須手動編程。 - 方便程序的測試
Spring對Junit4支持,可以通過注解方便的測試Spring程序。 - 方便集成各種優秀的框架
Spring不排斥各種優秀的開源框架,其內部提供了對各種優秀框架(如:Struts2、Hibernate、MyBatis、Quartz等)的直接支持。 - 降低JavaEE API的使用難度
Spring對JavaEE開發中非常難用的一些API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些API應用難度大大降低。
三、使用Spring的好處
上面我們就已詳細列出了使用Spring框架帶來的好處,我們僅就第三點進行詳細說明之。
當使用Spring框架時,我們可以使用容器提供的眾多服務。
試想若要是不使用Spring框架,那么使用Hibernate框架進行事務操作就應是:
Hibernate的事務操作:
public void save(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Info info = new Info("Spring框架");
info.setContent("學習Spring框架");
session.save(info);
session.getTransaction().commit();
}
既不使用Spring框架,也不使用Hibernate框架,直接使用最原始的JDBC技術進行事務操作,代碼就應是:
JDBC的事務操作:
Connection conn = null;
try {
......
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.executeUpdate("update person where name='葉天'");
conn.commit();
......
} catch (Exception e) {
conn.rollback();
} finally {
conn.close();
}
而如果使用Spring框架,那我們就不再需要手工控制事務了。另外,如果使用Spring框架,我們也不需要處理復雜的事務傳播行為了。我們舉例子來說明之。
例如,有代碼:
public void payment(){
Bean1.update(); // 更新金額
Bean2.save(); // 記錄操作日志
}
public class Bean1 {
public void update(){ // 注意:下面省略了一些代碼
Connection conn = null;
conn.setAutoCommit(false);
Statement.executeUpdate("update account set amount=? where id=?");
}
}
public class Bean2 {
public void save(){ // 注意:下面省略了一些代碼
Connection conn = null;
conn.setAutoCommit(false);
Statement.executeUpdate("insert into Log (content) values (?)");
}
}
如果我們不使用Spring框架,針對下面這兩種業務需求,我們該如何做呢?
- 第1種可能的業務需求:要求Bean1.update()和Bean2.save()在同一個事務中執行。
- 第2種可能的業務需求:要求不管Bean1.update()的事務是否成功,都需要記錄操作日志。
若要是不使用Spring框架,針對第1種可能的業務需求,我們的解決辦法用代碼來表示就是:
public void payment(){
Connection conn = null;
conn.setAutoCommit(false);
Bean1.update(conn); // 更新金額
Bean2.save(conn); // 記錄操作日志
// ...提交或回滾事務
}
public class Bean1 {
public void update(Connection conn){ // 注意:下面省略了一些代碼
Statement.executeUpdate("update account set amount=? where id=?");
}
}
public class Bean2 {
public void save(Connection conn){ // 注意:下面省略了一些代碼
Statement.executeUpdate("insert into Log (content) values (?)");
}
}
針對第2種可能的業務需求,我們不需要修改代碼就可完成,因為Bean1.update()開啟了一個事務,Bean2.save()同樣也開啟了一個事務,Bean1.update()開啟的事務的回滾不會影響到Bean2.save()開啟的事務。
倘若使用Spring框架,我們只需要通過聲明式的事務屬性配置就可以輕松地實現這兩種業務需求。
要求Bean1.update()和Bean2.save()在同一個事務中執行。我們只須將代碼改為:
@Transactional(propagation=Propagation.Required)
public void payment(){
Bean1.update(); // 更新金額
Bean2.save(); // 記錄日志
}
public class Bean1 {
@Transactional(propagation=Propagation.Required)
public void update(){
executeUpdate("update account set amount=? where id=?");
}
}
public class Bean2 {
@Transactional(propagation=Propagation.Required)
public void save(){
executeUpdate("insert into Log (content) values (?)");
}
}
要求不管Bean1.update()的事務是否成功,都需要記錄日志。我們只須將代碼改為:
@Transactional(propagation=Propagation.Required)
public void payment(){
Bean1.update(); // 更新金額
Bean2.save(); // 記錄日志
}
public class Bean1 {
@Transactional(propagation=Propagation.Required)
public void update(){
executeUpdate("update account set amount=? where id=?");
}
}
public class Bean2 {
@Transactional(propagation=Propagation.RequiresNew)
public void save(){
executeUpdate("insert into Log (content) values (?)");
}
}
四、Spring的入門案例
IOC的底層實現原理
IOC:Inversion of Control,控制反轉。指的是對象的創建權反轉(交給)給Spring,其作用是實現了程序的解耦合。也可這樣解釋:獲取對象的方式變了。對象創建的控制權不是“使用者”,而是“框架”或者“容器”。
用更通俗的話來說,IOC就是指對象的創建,并不是在代碼中用new操作new出來的,而是通過Spring進行配置創建的。其底層實現原理是XML配置文件+SAX解析+工廠設計模式。
直接用new操作創建對象為什么不好呢(Sping為什么使用依賴注入而不使用實例化對象的方式)? ?
spring對業務邏輯類和Dao類使用注入,是因為這些類不需要存儲功能,只需要能夠使用這些類中的處理方法就行了。若是使用new,那么每次進行業務處理都要new一個對象,不僅降低效率而且占用更多的資源。另外實現程序的解耦合,在一些復雜的系統中,一個對象A可能依賴于對象B,C等(代碼表現為A類持有B,C類的對象作為A類的屬性),以往來說,我們想要使用B,C中的方法時,就要先new出BC的對象,再去調用方法。我們并不想在A類中new出B,C的對象,這樣會增加類之間的耦合性。
就拿持久層(也即dao(data access object,數據訪問對象)層)的開發來說,官方推薦做法是先創建一個接口,然后再創建接口對應的實現類。
先創建一個Userdao接口
public interface UserDao {
public void add();
}
再創建Userdao接口的UserDaoImpl實現類
public class UserDaoImpl implements UserDao {
public void add() {
balabala......
}
}
接著我們在service層調用dao層,核心代碼如下:
// 接口 實例變量 = new 實現類
UserDao dao = new UserDaoImpl();
dao.add();
可發現缺點:service層和dao層耦合度太高了。解決方法是使用工廠模式進行解耦合操作。
創建一個工廠類,在工廠類中提供一個方法,返回實現類的對象。
public class Factory {
// 提供返回實現類對象的方法
public static UserDao getUserDaoImpl() {
return new UserDaoImpl();
}
}
然后在service層調用dao層的核心代碼就變為:
UserDao dao = Factory.getUserDaoImpl();
dao.add();
如若這樣做,會發現又產生了一個缺點:service層和工廠類又耦合了。所以使用工廠模式進行解耦合也只是一種權宜之計。下面我就來簡單講講Spring IOC的底層實現原理:
配置文件中可能會有如下配置信息:
<bean id="userDaoImpl" class="cn.itcast.dao.impl.UserDaoImpl" />
也是要創建一個工廠類,在工廠類中提供一個返回實現類對象的方法,但并不是直接new實現類,而是使用SAX解析配置文件,根據標簽bean中的id屬性值得到對應的class屬性值,使用反射創建實現類對象。
public class Factory {
public static UserDao getUserDaoImpl() {
// 1.使用SAX解析得到配置文件內容
// 直接根據id值userDaoImpl得到class屬性值
String classvalue = "class屬性值";
// 2.使用反射得到對象
Class clazz = Class.forName(classvalue);
UserDaoImpl userDaoImpl = (UserDaoImpl)lazz.newInstance();
return userDaoImpl;
}
}
面向對象設計的七大原則
這里我稍微講一下面向對象設計的七大原則,不必強記,重在理解。
- 單一職責原則(Single Responsibility Principle):每一個類應該專注于做一件事情。
- 里氏替換原則(Liskov Substitution Principle):超類存在的地方,子類是可以替換的。
- 依賴倒置原則(Dependence Inversion Principle):實現盡量依賴抽象,不依賴具體實現。
- 接口隔離原則(Interface Segregation
Principle):應當為客戶端提供盡可能小的單獨的接口,而不是提供大的總的接口。 - 迪米特法則(Law Of Demeter):又叫最少知識原則,一個軟件實體應當盡可能少的與其他實體發生相互作用。
- 開閉原則(Open Close Principle):面向擴展開放,面向修改關閉。
- 組合/聚合復用原則(Composite/Aggregate Reuse Principle
CARP):盡量使用組合/聚合達到復用,盡量少用繼承。原則: 一個類中有另一個類的對象。
Spring的IOC入門
步驟一:下載Spring的開發包
Spring的官網是http://spring.io。Spring的開發包的下載地址是http://repo.springsource.org/libs-release-local/org/springframework/spring,我下載的是spring-framework-4.2.4.RELEASE。解壓縮之后,可發現Spring開發包的目錄結構如下:
- docs:API和開發規范
- libs:Jar包和源碼
- schema:約束
步驟二:創建Web項目,引入Spring的開發包
從下圖可知:
由于我們只是初次入門Spring,所以也只是使用Spring的基本功能,所以需要使用到下面的這4個Jar包:
除此之外,還要導入Spring支持的日志Jar包:
步驟三:編寫相關的類,在類中創建方法
在src目錄下創建一個cn.itcast.ioc包,并在該包下創建一個User類。
public class User {
public void add() {
System.out.println("add.................");
}
}
步驟三:創建Spring配置文件
注意:Spring配置文件的名稱和位置沒有固定要求,一般建議把該文件放到src下面,名稱可隨便寫,官方建議寫成applicationContext.xml。但我覺得這個文件名稱太長了,所以決定寫為bean1.xml。然后我們還需要在配置文件中引入約束,Spring學習階段的約束是schema約束。那么問題來了,這個約束又該怎么寫呢?可參考docs\spring-framework-reference\html目錄下的xsd-configuration.html文件,在其內容最后找到如下內容:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<bean id="foo" class="x.y.Foo">
<meta key="cacheName" value="foo"/>
<property name="name" value="Rick"/>
</bean>
</beans>
然后將其復制黏貼到配置文件bean1.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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
步驟四:在配置文件中配置對象的創建
<!-- 1.配置user對象的創建 -->
<bean id="user" class="cn.itcast.ioc.User"></bean>
步驟五:編寫測試程序
我們要在Spring中寫代碼來實現獲取bean1.xml文件中配置的對象(該段代碼不要求重點掌握,只是用在測試中而已)。這段代碼主要用來解析Spring配置文件得到對象,但這個過程不需要我們寫代碼實現,Spring封裝了一個對象幫我們進行了這些操作,這個對象叫ApplicationContext,它就能實現這個功能。
在cn.itcast.ioc包下創建一個TestIOC單元測試類,如下:
public class TestIOC {
// 得到配置的user對象
@Test
public void demo1() {
// 1.加載Spring配置文件,把配置文件中的對象進行創建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml"); // classpath:類路徑,src目錄下的文件最終要編譯到類路徑下
// 2.根據配置文件的id得到user對象
User user = (User) context.getBean("user");
System.out.println(user);
user.add();
}
}
注意:classpath為類路徑,src目錄下的文件最終要編譯到類路徑下。
Spring的bean管理
通俗一點說,Spring的bean管理即指創建對象時不需要new操作代碼實現,而是交給Spring進行配置完成。
Spring進行bean管理有兩種方式:
- 使用配置文件方式實現
- 使用注解方式實現
本文將重點放在第一種方式上,后一種方式后面會講。
Spring實例化bean的三種方式
- 使用無參構造(重點)
創建對象時候,調用類里面的無參數的構造方法實現。那么Spring配置文件中又該怎樣寫呢?基本類似于如下寫法:
<!-- 1.配置user對象的創建 -->
<bean id="user" class="cn.itcast.ioc.User"></bean>
- 使用靜態工廠(了解)
創建一個工廠類,在工廠類中提供一個靜態的方法,這個方法返回類的對象;調用工廠類的方法時候,直接使用類名.方法名稱即可以調用。下面舉例來說明。
在src目錄下創建一個cn.itcast.bean包,并在該包下創建一個Bean1類。
public class Bean1 {
public void bean1() {
System.out.println("bean1..........");
}
}
然后在該包下創建一個Bean1Factory工廠類。
public class Bean1Factory {
// 靜態方法
public static Bean1 getBean1() {
return new Bean1();
}
}
接著Spring配置文件中應向下面這樣配置:
<!-- 2.使用靜態工廠創建對象 -->
<bean id="bean1" class="cn.itcast.bean.Bean1Factory" factory-method="getBean1"></bean>
最后在該包下創建一個TestIOC單元測試類。
public class TestIOC {
@Test
public void demo1() {
// 1.加載Spring配置文件,把配置文件中的對象進行創建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
// 2.根據配置文件的id得到user對象
Bean1 bean1 = (Bean1) context.getBean("bean1");
System.out.println(bean1);
}
}
- 使用實例工廠(了解)
創建一個工廠類,在工廠類里面提供一個普通的方法,這個方法返回類對象;調用工廠類的方法時候,創建工廠類對象,使用對象調用方法即可。下面也舉例來說明。
在src目錄下的cn.itcast.bean包下創建一個Bean2類。
public class Bean2 {
public void bean2() {
System.out.println("bean2..........");
}
}
然后在該包下創建一個Bean2Factory工廠類。
public class Bean2Factory {
public Bean2 getBean2() {
return new Bean2();
}
}
接著Spring配置文件中應向下面這樣配置:
<!-- 3.使用實例工廠創建對象 -->
<!-- 3.1先創建工廠對象 -->
<bean id="bean2Factory" class="cn.itcast.bean.Bean2Factory"></bean>
<!-- 3.2再使用工廠對象創建bean2對象 -->
<bean id="bean2" factory-bean="bean2Factory" factory-method="getBean2"></bean>
最后將TestIOC單元測試類的代碼修改為:
public class TestIOC {
@Test
public void demo1() {
// 1.加載Spring配置文件,把配置文件中的對象進行創建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
// 2.根據配置文件的id得到user對象
Bean2 bean2 = (Bean2) context.getBean("bean2");
System.out.println(bean2);
}
}
Spring配置文件中bean標簽常用的屬性
Spring配置文件中bean標簽常用的屬性有以下四種:
- id屬性:根據id屬性值得到配置對象。
在Spring配置文件中會有多個bean標簽,但它們的id屬性值是不能相同的。Bean起名字時,在約束中采用的是ID約束——唯一,而且名字必須以字母開始,可以使用字母、數字、連字符、下劃線、句號、冒號等,但id屬性值不能有特殊符號。 - class屬性:要創建對象的類的全路徑。
- name屬性:name屬性的功能和id屬性是一樣的。name屬性和id屬性區別是:在id屬性值里面不能有特殊符號,在name屬性值里面可以添加特殊符號。
- scope屬性:bean的作用范圍。
scope屬性共有以下5個屬性:
1.singleton:創建的對象是單例的,指一個Bean容器中只有一份,也是scope屬性的默認值。
下面我來舉例說明它。將TestIOC單元測試類的代碼修改為:
public class TestIOC {
// 得到配置的user對象
@Test
public void demo1() {
// 1.加載Spring配置文件,把配置文件中的對象進行創建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
// 2.根據配置文件的id得到user對象
User user1 = (User) context.getBean("user");
User user2 = (User) context.getBean("user");
System.out.println(user1);
System.out.println(user2);
}
}
單元測試以上方法,一切就盡在不言中。其實,此時Spring配置文件中有關如下bean的配置:
<bean id="user" class="cn.itcast.ioc.User"></bean>
就相當于:
<bean id="user" class="cn.itcast.ioc.User" scope="singleton"></bean>
2.prototype:每次請求(每次使用)創建新的實例,destroy方式不生效,創建的對象是多實例的。
也可舉例來說明它。將Spring配置文件中有關如下bean的配置:
<bean id="user" class="cn.itcast.ioc.User"></bean>
修改為:
<bean id="user" class="cn.itcast.ioc.User" scope="prototype"></bean>
測試單元測試類的方法就能明白了。
3.globalSession:用在單點登錄(即SSO,single sign on)上。
4.request:每次http請求創建一個實例但僅在當前request內有效。
5.session:每次http請求創建一個實例但僅在當前session內有效。
bean的生命周期的配置
通過配置<bean>
標簽上的init-method
作為bean的初始化的時候執行的方法,配置destroy-method
作為bean的銷毀的時候執行的方法。銷毀方法想要執行,需要是單例創建的Bean而且在工廠關閉的時候,Bean才會被銷毀。
Spring中Bean的屬性注入
實際上,有關Bean的屬性注入共有三種方式,下面我分別加以簡單的說明:
- set方法注入
用代碼可表示如下:
public class Book {
private String bookname;
public void setBookname(String bookname) {
this.bookname = bookname;
}
}
Book book = new Book();
book.setBookName("Java編程思想");
- 有參數構造注入
用代碼可表示如下:
public class Book {
private String bookname;
public Book(String bookname) {
this.bookname = bookname;
}
}
Book book = new Book("代碼大全");
- 接口注入
先編寫一個接口:
public interface Dao {
public void add(String name);
}
再編寫這個接口的實現類:
public class DaoImpl implements Dao {
private String name;
public void add(String name) {
this.name = name;
}
}
但在Spring框架里面,只支持前兩種方式,即set方法注入和有參數構造注入。下面我來舉例分別演示。
- 構造方法的方式注入屬性
在src目錄下創建一個cn.itcast.property包,并在該包下編寫一個Book實體類。
public class Book {
private String bookname;
public Book(String bookname) {
this.bookname = bookname;
}
public void testBook() {
System.out.println("book.............." + bookname);
}
}
接著在Spring配置文件中對以上JavaBean添加如下配置:
<!-- 4.使用有參數的構造注入屬性 -->
<bean id="book" class="cn.itcast.property.Book">
<!-- 使用標簽,name:為屬性的名字;value:為屬性的值 -->
<constructor-arg name="bookname" value="beautifulMan_美美俠"></constructor-arg>
</bean>
最后在該包下編寫一個TestIOC單元測試類:
public class TestIOC {
@Test
public void demo1() {
// 1.加載Spring配置文件,把配置文件中的對象進行創建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
Book book = (Book) context.getBean("book");
book.testBook();
}
}
自己自行測試去吧!
- set方法的方式注入屬性
我們同樣在cn.itcast.property包下編寫一個Person實體類,在類中定義屬性,并生成set方法。
public class Person {
// 1.定義一個屬性
private String username;
// 2.生成這個屬性的set方法
public void setUsername(String username) {
this.username = username;
}
public void testperson() {
System.out.println("person.............." + username);
}
}
然后在Spring配置文件中,使用bean標簽創建對象,在bean標簽里面使用property標簽注入屬性。即在Spring配置文件中對以上JavaBean添加如下配置,
<!-- 5.使用set方法進行注入屬性 -->
<bean id="person" class="cn.itcast.property.Person">
<!--
使用property標簽注入屬性值
name:類屬性名稱
value屬性:往屬性中注入的值
-->
<property name="username" value="李阿昀"></property>
</bean>
最后將TestIOC單元測試類的代碼修改為:
public class TestIOC {
@Test
public void demo1() {
// 1.加載Spring配置文件,把配置文件中的對象進行創建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
Person person = (Person)context.getBean("person");
person.testperson();
}
}
自己自行測試去吧!
Spring的屬性注入:對象類型的注入
在實際開發中,我們要提交表單到action里面去,然后在action里面調用service層的方法,接著在service層里面調用dao層的方法。在這里,我假設在service層里面調用dao層的方法,所以需要在servcie層里面創建dao層的對象實現調用。
先在src目錄下創建一個cn.itcast.dao包,并在該包下編寫一個UserDao類。
public class UserDao {
public void add() {
System.out.println("dao................");
}
}
然后在src目錄下再創建一個cn.itcast.service包,并在該包下編寫一個UserService類。
public class UserService {
public void add() {
System.out.println("service.........");
// 調用dao
balabala......
}
}
如果我們使用最原始的方式在service層里面調用dao層的方法,那么UserService類中add()方法應這樣寫:
public void add() {
System.out.println("service.........");
// 原始方式,調用dao
UserDao dao = new UserDao();
dao.add();
}
在Spring里面,我們就應該這么玩了。我們的最終目的是在service層里面得到dao層對象。所以步驟為:
第一步,讓dao作為service的一個屬性。
// 1.讓dao作為service的一個屬性
private UserDao userDao;
第二步,生成dao屬性的set方法。
// 2.生成dao屬性的set方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
這時,UserService類的代碼就變成:
public class UserService {
// 1.讓dao作為service的一個屬性
private UserDao userDao;
// 2.生成dao屬性的set方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add() {
System.out.println("service.........");
userDao.add();
}
}
在Spring配置文件中進行配置和注入。
<!-- 6.注入對象的屬性 -->
<!-- 6.1先創建dao對象 -->
<bean id="userDao" class="cn.itcast.dao.UserDao"></bean>
<!-- 6.2再創建service對象 -->
<bean id="userService" class="cn.itcast.service.UserService">
<!-- 在servcie里面注入userDao屬性
name屬性:service對象里面的userDao屬性的名稱
注入dao對象,不能寫value屬性,要寫ref屬性:dao配置的bean的id值
-->
<property name="userDao" ref="userDao"></property>
</bean>
名稱空間p的屬性注入方式——Spring2.x版本后提供的方式
在src目錄下創建一個cn.itcast.propertydemo包,并在該包下編寫一個Orders實體類。
public class Orders {
private String oname;
public void setOname(String oname) {
this.oname = oname;
}
public void testorders() {
System.out.println("orders................" + oname);
}
}
接下來我們需要在Spring核心配置文件中的schema約束位置定義p名稱空間。
xmlns:p="http://www.springframework.org/schema/p"
緊接著,我們需要在Spring核心配置文件中添加如下配置:
<!-- 7.p(property,屬性)名稱空間的注入 -->
<bean id="orders" class="cn.itcast.propertydemo.Orders" p:oname="去你媽的!!!"></bean>
最后將cn.itcast.property包下的TestIOC單元測試類的代碼修改為:
public class TestIOC {
@Test
public void demo1() {
// 1.加載Spring配置文件,把配置文件中的對象進行創建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
Orders orders = (Orders)context.getBean("orders");
orders.testorders();
}
}
測試即可。
結論——使用p名稱空間:
普通屬性:p:屬性名稱=”…”
對象類型的屬性:p:屬性名稱-ref=”…”
注入復雜屬性
- 注入數組類型的屬性
將cn.itcast.propertydemo包下的Orders類的代碼修改為:
public class Orders {
private String oname;
public void setOname(String oname) {
this.oname = oname;
}
// 1.數組類型的屬性
private String[] arrays;
public void setArrays(String[] arrays) {
this.arrays = arrays;
}
public void testorders() {
// System.out.println("orders................" + oname);
System.out.println("數組:" + Arrays.toString(arrays));
}
}
然后需要在Spring核心配置文件中添加如下配置:
<bean id="orders" class="cn.itcast.propertydemo.Orders"> <!-- 創建對象 -->
<!-- 數組類型 -->
<property name="arrays"> <!-- 注入屬性 -->
<list>
<value>葉子</value>
<value>liayun</value>
<value>杰哥</value>
</list>
</property>
</bean>
最后將cn.itcast.property包下的TestIOC單元測試類的代碼修改為:
public class TestIOC {
@Test
public void demo1() {
// 1.加載Spring配置文件,把配置文件中的對象進行創建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
Orders orders = (Orders)context.getBean("orders");
orders.testorders();
}
}
測試即可。
- 注入List集合類型的屬性
將cn.itcast.propertydemo包下的Orders類的代碼修改為:
public class Orders {
private String oname;
public void setOname(String oname) {
this.oname = oname;
}
// 2.list類型的屬性
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
public void testorders() {
// System.out.println("orders................" + oname);
System.out.println("list:" + list);
}
}
然后需要在Spring核心配置文件中添加如下配置:
<bean id="orders" class="cn.itcast.propertydemo.Orders"> <!-- 創建對象 -->
<!-- list類型 -->
<property name="list">
<list>
<value>葉子</value>
<value>李昀玲</value>
<value>杰哥</value>
</list>
</property>
</bean>
cn.itcast.property包下的TestIOC單元測試類的代碼勿須修改,直接測試即可。
- 注入Set集合類型的屬性
將cn.itcast.propertydemo包下的Orders類的代碼修改為:
public class Orders {
private String oname;
public void setOname(String oname) {
this.oname = oname;
}
// 3.set類型的屬性
private Set<String> keyset;
public void setKeyset(Set<String> keyset) {
this.keyset = keyset;
}
public void testorders() {
// System.out.println("orders................" + oname);
System.out.println("set:" + keyset);
}
}
然后需要在Spring核心配置文件中添加如下配置:
<bean id="orders" class="cn.itcast.propertydemo.Orders"> <!-- 創建對象 -->
<!-- set類型 -->
<property name="keyset">
<set>
<value>蝙蝠俠</value>
<value>鋼鐵俠</value>
<value>美美俠</value>
</set>
</property>
</bean>
其實,以上配置也可以寫為:
<bean id="orders" class="cn.itcast.propertydemo.Orders"> <!-- 創建對象 -->
<!-- set類型 -->
<property name="keyset">
<list>
<value>蝙蝠俠</value>
<value>鋼鐵俠</value>
<value>美美俠</value>
</list>
</property>
</bean>
cn.itcast.property包下的TestIOC單元測試類的代碼勿須修改,直接測試即可。
- 注入Map集合類型的屬性
將cn.itcast.propertydemo包下的Orders類的代碼修改為:
public class Orders {
private String oname;
public void setOname(String oname) {
this.oname = oname;
}
// 4.map類型
private Map<String, String> map;
public void setMap(Map<String, String> map) {
this.map = map;
}
public void testorders() {
// System.out.println("orders................" + oname);
System.out.println("map:" + map);
}
}
然后需要在Spring核心配置文件中添加如下配置:
<bean id="orders" class="cn.itcast.propertydemo.Orders"> <!-- 創建對象 -->
<!-- map類型 -->
<property name="map">
<map>
<entry key="username" value="潘金蓮"></entry>
<entry key="password" value="1314"></entry>
<entry key="address" value="明初"></entry>
</map>
</property>
</bean>
cn.itcast.property包下的TestIOC單元測試類的代碼勿須修改,直接測試即可。
- 注入Properties類型的屬性
將cn.itcast.propertydemo包下的Orders類的代碼修改為:
public class Orders {
private String oname;
public void setOname(String oname) {
this.oname = oname;
}
// 5.properties
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
public void testorders() {
// System.out.println("orders................" + oname);
System.out.println("properties:" + properties);
}
}
然后需要在Spring核心配置文件中添加如下配置:
<bean id="orders" class="cn.itcast.propertydemo.Orders"> <!-- 創建對象 -->
<!-- properties類型 -->
<property name="properties">
<props>
<prop key="name">宮本一郎</prop>
<prop key="address">日本</prop>
</props>
</property>
</bean>
cn.itcast.property包下的TestIOC單元測試類的代碼勿須修改,直接測試即可。
IoC和DI的區別
IoC:控制反轉,即把對象的創建交給Spring進行管理。所以Spring IoC容器是用來創建對象,管理依賴關系的。
DI(Dependency Injection):依賴注入,即在創建對象的過程中,向類里面的屬性中設置值。
IoC和DI的關系:依賴注入不能單獨存在,須在控制反轉基礎之上完成,用更通俗點的話來說,就是注入類里面的屬性值,不能直接注入,須創建類的對象再完成注入。
Spring中的工廠
ApplicationContext
ApplicationContext接口有兩個實現類,如下圖:
- ClassPathXmlApplicationContext:加載的是類路徑下的Spring配置文件
- FileSystemXmlApplicationContext:加載的是本地磁盤下的Spring配置文件
BeanFactory
下面應該是BeanFactory類的繼承體系圖吧!
稍微了解一下就好,這個類在實際開發中我們并不需要用到。
ApplicationContext和BeanFactory的區別
雖然使用這兩個對象都可以加載Spring的配置文件,并創建配置文件中的對象。但他倆還是有區別的,最主要的區別是:
- 使用applicationContext操作時,可把Spring里面的配置文件中的對象都進行創建。
- 使用BeanFactory對象操作時,在調用getBean方法的時候進行對象的創建。
五、Spring整合Web項目的底層原理
在實際的開發中,我們一般會使用SSH(即Struts2、Spring、Hibernate)進行開發,然后創建Spring的配置文件,使用applicationContext對象加載配置文件,繼而創建對象。在真正的開發中,我們一般不會直接寫applicationContext代碼加載配置文件。
Spring整合Web項目的思想
在服務器啟動的時候,加載Spring配置文件,并創建對象。
Spring整合Web項目的底層原理
Spring整合Web項目用到以下兩個技術:
- 使用ServletContext對象(在服務器啟動時創建)
- 使用監聽器
在服務器啟動的時候,每個項目都會創建一個ServletContext對象,而且每個項目只有一個ServletContext對象。在ServletContext對象創建的時候,使用監聽器可以監聽到其創建。當我們監聽到ServletContext對象創建時,Spring就會幫我們做一件事情——加載Spring配置文件,并把配置文件中的對象進行創建,對象創建之后,放到ServletContext域里面去,最終我們要使用創建的對象,可從ServletContext域里面獲取出來。
智能推薦
Spring框架入門分析
定位 輕量級的企業級 Java 應用程序開發框架,基礎版本只有 2 MB 左右的大小。核心特性是可以用于開發任何 Java 應用程序,但是在 Java EE 平臺上構建 web 應用程序是需要擴展的。 Spring 框架的目標是使 J2EE 開發變得更容易使用,通過啟用基于 POJO 編程模型來促進良好的編程實踐。 架構分析:Core Containe IOC容器: Spring BeanFact...
spring框架入門學習
1. Spring概述 1.1. Spring是什么 Spring是一個開放源代碼的設計層面框架,他解決的是業務邏輯層和其他各層的松耦合問題, 因此它將面向接口的編程思想貫穿整個系統應用。Spring是于2003 年興起的一個輕量級的Java 開發框架, 由Rod Johnson創建。簡單來說,Spring是一個分層的JavaSE/EEfull-stack(一站式...
框架入門-spring01
目前的主流框架: SSH:spring strust2 hibernate SSM:spring springMVC MyBatis 三層架構: 表示層--jsp(springMVC/struts) 業務邏輯層--servi...
Spring框架入門(二)—— AOP
1 AOP介紹 1.1 什么是AOP 在軟件業,AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是OOP(面向對象編程)的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生范型...
猜你喜歡
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...