控制的什么被反轉了?就是獲得依賴對象的方式被反轉了——Martin Fowler
1、Spring基本知識
1.1 什么是Spring?
- Spring是分層JavaSE/EE full-stack輕量級開源框架
- 以IoC(Inverse of Control,控制反轉)和AOP(Aspect Oriented Programing,面向切面編程)為核心
- 實際開發中,通常采用三層體系架構(web、service、dao)。spring對每一層都提供了技術支持,在表示層提供了與struts2框架的整合,在業務邏輯層可以管理事務、記錄日志等,在持久層可以整合Hibernate、JdbcTemplate等技術
1.2 Spring框架的優點
- 方便解耦,簡化開發 (高內聚低耦合) Spring就是一個大工廠(容器),可以將所有對象創建和依賴關系維護,交給Spring管理spring工廠是用於生成bean
- AOP編程的支持 Spring提供面向切面編程,可以方便的實現對程序進行權限攔截、運行監控等功能
- 聲明式事務的支持 只需要通過配置就可以完成對事務的管理,而無需手動編程
- 方便程序的測試 Spring對Junit4支持,可以通過注解方便的測試Spring程序
- 方便集成各種優秀框架 Spring不排斥各種優秀的開源框架,其內部提供了對各種優秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
- 降低JavaEE API的使用難度 Spring 對JavaEE開發中非常難用的一些API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些API應用難度大大降低
1.3 Spring的體系結構
核心容器:beans、core、context、expression
1.4 Spring的下載及目錄結構
下載地址:http://repo.spring.io/simple/libs-release-local/org/springframework/spring/3.2.0.RELEASE
目錄結構:
libs中有50多個jar文件,有4個Spring的基礎包,分別對應Spring核心容器的4個模塊
spring-core-3.2.0.RELEASE.jar 包含Spring框架基本的核心工具類,Spring其他組件都要用到這個包里的類,是其他組件的基本核心
spring-beans-3.2.0.RELEASE.jar 所有應用都要用到的,它包含訪問配置文件、創建和管理bean以及進行IoC或者DI操作相關的類
spring-context-3.2.0.RELEASE.jar 在基礎IoC功能上的擴展服務
spring-expression-3.2.0.RELEASE.jar 定義了Spring的表達式語言
2. 入門案例:IoC
2.1 導入jar包 4核心+1依賴
2.2 目標類
UserDao接口
public interface UserDao { public void addUser(); }
UserDaoImpl實現類
public class UserDaoImpl implements UserDao { @Override public void addUser() { System.out.println("添加用戶"); } }
2.3 配置文件
spring幫我們創建對象,但也必須有相關類的信息,不然怎么能夠創建呢?
配置文件名稱:建議:ApplicationContext.xml,取別的也可以,但是取建議的名稱的話,找到該配置文件更為簡單,
配置文件位置:任意,一般都在classpath下(src)
文件約束內容:添加約束,spring-framework-3.2.0.RELEASE 為spring的核心 docs為幫助文檔
約束位置:spring-framework-3.2.0.RELEASE\docs\spring-framework-reference\html\xsd-config.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="userDao" class="com.tcxpz.spring_chapter01.ioc.UserDaoImpl"></bean> </beans>
2.4 測試
public class TestIoC { @Test public void demo(){ /* * 以前的做法是 UserDao userDao = new UserDaoImpl() * 現在交給Spring來創建,程序從Spring容器中獲取 */ //1 定義配置文件的路徑(項目中一般放在src目錄下,此處為方便放在包下) String xmlPath = "com/tcxpz/spring_chapter01/ioc/applicationContext.xml"; //2 初始化Spring容器,加載配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); //3 通過容器獲取userDao實例 UserDao userDao = (UserDao) applicationContext.getBean("userDao"); //調用userDao的addUser()方法 userDao.addUser(); } }
測試結果:
3 入門案例2:DI
依賴注入(DI):spring創建對象A時,會將對象A所依賴的對象B也創建出來,並自動注入到對象A中。
依賴:(has a) 有一個的意思,比如類A中有一個類B,那么就說A依賴B。
繼承,實現:(is a)
當出現一個類依賴於另一個類時,之前的開發是這樣的
public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoImpl(); @Override public void save() { userDao.addUser(); } }
學習了Spring之后,開發就是這樣的了
public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void save() { userDao.addUser(); } }
3.1 導入jar包(同2.1)
3.2 目標類
UserDao接口與UserDaoImp實現類(同2.2)
UserService接口與UserServiceImpl實現類
public interface UserService { public void save(); }
public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void save() { userDao.addUser(); } }
3.3 配置文件
<?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"> <!-- 創建UserDao對象 --> <bean id="userDao" class="com.tcxpz.spring_chapter01.di.UserDaoImpl"></bean> <!-- 創建Service對象 --> <bean id="userService" class="com.tcxpz.spring_chapter01.di.UserServiceImpl"> <!-- <property> 用於進行屬性注入 name: bean的屬性名,通過setter方法獲得 setBookDao ##> BookDao ##> bookDao ref :依賴的另一個bean的id值的引用 --> <property name="userDao" ref="userDao"></property> </bean> </beans>
3.4 測試
public class TestDI { @Test public void demo(){ String xmlPath = "com/tcxpz/spring_chapter01/di/applicationContext.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); UserService userService = (UserService) applicationContext.getBean("userService"); userService.save(); } }
測試結果
4 Spring中的bean
4.1 Bean的配置
可以把Spring看做一個大型的工廠,而Spring容器中的bean就是該工廠的產品
Spring容器支持兩種格式的文件,分別為Properties文件格式和XML文件格式,在實際開發中,最常用的是XML文件格式的配置方式
每一個<bean>子元素定義了一個bean,並且描述了該bean如何被裝配到Spring容器中。<bean>中包含很多屬性:id,name,class,scope,constructor-arg,property,ref,value,list,set,map,entry
4.2 Bean的實例化
並不是每個bean都是普通類,有些是通過工廠來獲取的,而工廠就有靜態工廠和實例工廠,所以spring創建實例對象有三種情況,
默認無參構造:直接<bean id="" class="">,必須提供無參的構造方法
靜態工廠:由於是靜態工廠,所以通過工廠類直接調用創建實例的靜態方法就可以了,不需要創建工廠的實例對象。
<bean id="" class="工廠全限定類名" factory-method="靜態方法">
實例工廠:需要先創建出工廠實例對象,然后再由工廠實例對象的方法創建對象,所以會有兩個Bean
<bean id="myFactoryId" class="工廠全限定類名"></bean>
<bean id="" factory-bean="myFactoryId" factory-method=""></bean>
4.3 Bean的作用域
作用域的種類:singleton prototype request session global
主要掌握前兩個即可
單例模式(singleton):使用singleton定義的Bean在Spring容器中只有一個實例,也就是說,無論有多少個Bean引用它,始終指向同一個對象(默認作用域)
public class TestDI { @Test public void demo(){ String xmlPath = "com/tcxpz/spring_chapter01/di/applicationContext.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); UserService userService1 = (UserService) applicationContext.getBean("userService"); UserService userService2 = (UserService) applicationContext.getBean("userService"); System.out.println(userService1==userService2); } }
原型模式(prototype):每次通過Spring容器獲取的prototype定義的Bean時,容器都將創建一個新的實例。
4.4 Bean的生命周期
Spring容器可以管理singleton作用域下Bean的生命周期,再次作用於下,Spring能夠精確地知道該何時創建,何時初始化完成,以及何時被銷毀。
而對於prototype作用域的Bean,Spring只負責創建,當容器創建了Bean實例后,Bean的實例就交給客戶端代碼來管,Spring容器就不再跟蹤其生命周期。
4.5 Bean的裝配方式
Bean的裝配可以理解為依賴關系注入,Bean的裝配方式也就是Bean依賴注入的方式。主要有三種:基於XML 基於注解 自動裝配
4.5.1 基於XML的裝配
主要有兩種方式:setter注入和構造注入 setter注入時,Bean類必須提供一個默認的構造方法,而且必須為注入的屬性提供setter方法
(1)導包 4核心+1依賴
(2)創建User類
public class User { private String username; private Integer password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Integer getPassword() { return password; } public void setPassword(Integer password) { this.password = password; } //默認構造 public User(){ } //構造方法注入 public User(String username,Integer password){ super(); this.username=username; this.password=password; } @Override public String toString() { return "User [username=" + username + ", password=" + password + "]"; } }
(3)測試
public class TestUser { @Test public void demo(){ String xmlPath="com/tcxpz/spring_chapter01/domain/applicationContext.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); User user1 = (User) applicationContext.getBean("user1"); User user2 = (User) applicationContext.getBean("user2"); System.out.println(user1); System.out.println(user2); } }
不管是普通屬性還是引用數據,都可以通過構造方法進行注入。通過setter方法進行注入引用數據。
通過setter方法對普通屬性和引用屬性進行注入,那么要是創建的對象中有集合呢?那該如何進入注入?
集合的注入List、Map、Set、數組、Properties等。
list
set
map
數組:
properties
注意:集合之間可以相互嵌套,比如list中可能裝有對象(bean)等等
4.5.2 基於Annotation的裝配
注解格式:@xxx 開發中通常采用注解取代xml配置文件
使用注解:必須對使用注解的地方進行掃描,不然注解沒用。而掃描需要做兩件事
1、添加名稱空間
在我們找配置文件中約束的位置那:spring-framework-3.2.0.RELEASE\docs\spring-framework-reference\html\xsd-config.html 找到context的名稱空間。
2. 掃描指定的目錄
注解:
1、@Component 替代 <bean id="" class=""> 可以配置任意bean,在所在類上面添加該注解即可,
@Component("userId") userId相當於bean中的id屬性值
2、這三個就跟使用@Component是一樣的,但是為了更好的體現三層架構,就有了這三個注解
@Controller 修飾web層中的類。
@Service 修飾service層的類
@Repository 修飾dao層的類
兩種方式,一種不聲明名稱,一種聲明名稱
@Controller("xxx") @Controller
如果聲明了名稱,那么在別的地方引用的話,就可以使用@Autowired或@Autowired與@Qualifier的組合 或直接使用@Resource按照名稱注入
如果沒有聲明名稱,那么在別的地方引用的話,只能使用@Autowired 來進行注入
3、屬性注入
普通屬性
@Value @Value("") 給普通屬性注入屬性值
引用屬性
@Autowired 按默認類型進行注入
@Qualifier("") 按照名稱注入
如果使用了@Qualifier這個注解,那么就需要兩個一起使用才能生效。如果只使用@Autowired,那么寫不寫@Qualifier都可以
引用屬性
@Resource 直接按照名稱注入,與上面兩個注解一起使用是等效的
@Resource(name="xxx")
4、使用
5、其他注解
@Scope("prototype") 作用域注解(spring幫我們創建的bean實例的作用域,在下面會講解到)
@PostConstruct 修飾初始化
@PreDestory 修飾銷毀
最后兩個用的不多,掌握前面的即可。
4.5.3 P命令空間[了解]
對“setter方法注入”進行簡化,替換<property name="屬性名">,而是在<bean p:屬性名="普通值" p:屬性名-ref="引用值">
p命名空間使用前提,必須添加命名空間
<bean id="personId" class="com.itheima.f_xml.c_p.Person" p:pname="jack" p:age="22" p:homeAddr-ref="homeAddrId" p:companyAddr-ref="companyAddrId"> </bean> <bean id="homeAddrId" class="com.itheima.f_xml.c_p.Address" p:addr="北京" p:tel="010"> </bean> <bean id="companyAddrId" class="com.itheima.f_xml.c_p.Address" p:addr="合肥" p:tel="0551"> </bean>
4.5.4 SpEL[了解]
對<property>進行統一編程,所有的內容都使用value
<property name="" value="#{表達式}">
#{123}、#{'jack'} : 數字、字符串
#{beanId} :另一個bean引用
#{beanId.propName} :操作數據
#{beanId.toString()} :執行方法
#{T(類).字段|方法} :靜態方法或字段
5 myeclipse schema xml提示
步驟一:確定xsd文件位置:spring-framework-3.2.0.RELEASE\schema\beans
步驟二:復制路徑
步驟三:搜索“xml catalog”
步驟四:添加約束提示