---恢復內容開始---
1 spring框架概述
1.1 什么是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/EE full-stack(一站式) 輕量級開源框架。
l 輕量級:與EJB對比,依賴資源少,銷毀的資源少。
l 分層: 一站式,每一個層都提供的解決方案
web層:struts,spring-MVC
service層:spring
dao層:hibernate,mybatis , jdbcTemplate --> spring-data
1.2 spring核心
Spring的核心是控制反轉(IoC)和面向切面(AOP)
IoC(Inversion of control): 控制反轉控制權由對象本身轉向容器;由容器根據配置文件去創建實例並創建各個實例之間的依賴關系
AOP(Aspect Oriented Programming),也就是面向方面編程的技術。AOP基於IoC基礎,是對OOP的有益補充。
1.3spring優點
l 方便解耦,簡化開發 (高內聚低耦合)
l AOP編程的支持
l 聲明式事務的支持
l 方便程序的測試
l 方便集成各種優秀框架
l 降低JavaEE API的使用難度
|
1.4 spring體系結構
核心容器:beans、core、context、expression
1 入門案例:IoC【掌握】
1.1 導入jar包
l 4 + 1 : 4個核心(beans、core、context、expression) + 1個依賴(commons-loggins...jar)
1.2 目標類
l 提供UserService接口和實現類
l 獲得UserService實現類的實例
之前開發中,直接new一個對象即可。
學習spring之后,將由Spring創建對象實例--> IoC 控制反轉(Inverse of Control)
之后需要實例對象時,從spring工廠(容器)中獲得,需要將實現類的全限定名稱配置到xml文件中
public interface UserService {
public void addUser();
} |
public class UserServiceImpl implements UserService {
@Override public void addUser() { System.out.println("a_ico add user"); }
} |
1.3 配置文件
l 位置:任意,開發中一般在classpath下(src)
l 名稱:任意,開發中常用applicationContext.xml
l 內容:添加schema約束
約束文件位置: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"> <!-- 配置service <bean> 配置需要創建的對象 id :用於之后從spring容器獲得實例時使用的 class :需要創建實例的全限定類名 --> <bean id="userServiceId" class="com.zqy.a_ioc.UserServiceImpl"></bean> </beans> |
1.4 測試
@Test public void demo02(){ //從spring容器獲得 //1 獲得容器 String xmlPath = "com/zqy/a_ioc/beans.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); //2獲得內容 --不需要自己new,都是從spring容器獲得 UserService userService = (UserService) applicationContext.getBean("userServiceId"); userService.addUser();
} |
2 入門案例:DI【掌握】
l DI Dependency Injection ,依賴注入
is a :是一個,繼承。
has a:有一個,成員變量,依賴。
class B {
private A a; //B類依賴A類
}
依賴:一個對象需要使用另一個對象
注入:通過setter方法進行另一個對象實例設置。
l 例如:
class BookServiceImpl{
//之前開發:接口 = 實現類 (service和dao耦合)
//private BookDao bookDao = new BookDaoImpl();
//spring之后 (解耦:service實現類使用dao接口,不知道具體的實現類)
private BookDao bookDao;
setter方法
}
模擬spring執行過程
創建service實例:BookService bookService = new BookServiceImpl() -->IoC <bean>
創建dao實例:BookDao bookDao = new BookDaoImple() -->IoC
將dao設置給service:bookService.setBookDao(bookDao); -->DI <property>
2.1 目標類
l 創建BookService接口和實現類
l 創建BookDao接口和實現類
l 將dao和service配置 xml文件
l 使用api測試
2.1.1 dao
public interface BookDao {
public void addBook();
} |
public class BookDaoImpl implements BookDao {
@Override public void addBook() { System.out.println("di add book"); }
} |
2.1.2 service
public interface BookService {
public abstract void addBook();
} |
public class BookServiceImpl implements BookService {
// 方式1:之前,接口=實現類 // private BookDao bookDao = new BookDaoImpl(); // 方式2:接口 + setter private BookDao bookDao; public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; }
@Override public void addBook(){ this.bookDao.addBook(); }
} |
2.2 配置文件
<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"> <!-- 模擬spring執行過程 創建service實例:BookService bookService = new BookServiceImpl() IoC <bean> 創建dao實例:BookDao bookDao = new BookDaoImpl() IoC 將dao設置給service:bookService.setBookDao(bookDao); DI <property>
<property> 用於進行屬性注入 name: bean的屬性名,通過setter方法獲得 setBookDao ##> BookDao ##> bookDao ref :另一個bean的id值的引用 -->
<!-- 創建service --> <bean id="bookServiceId" class="com.zqy.b_di.BookServiceImpl"> <property name="bookDao" ref="bookDaoId"></property> </bean>
<!-- 創建dao實例 --> <bean id="bookDaoId" class="com.zqy.b_di.BookDaoImpl"></bean>
</beans> |
2.3 測試
@Test public void demo01(){ //從spring容器獲得 String xmlPath = "com/zqy/b_di/beans.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); BookService bookService = (BookService) applicationContext.getBean("bookServiceId");
bookService.addBook();
} |
3 myeclipse schema xml提示
l 步驟一:確定xsd文件位置
spring-framework-3.2.0.RELEASE\schema\beans
l 步驟二:復制路徑
l 步驟三:搜索“xml catalog”
l 步驟四:添加約束提示
4 核心API
l api整體了解,之后不使用,在學習過程需要。
l BeanFactory :這是一個工廠,用於生成任意bean。
采取延遲加載,第一次getBean時才會初始化Bean
l ApplicationContext:是BeanFactory的子接口,功能更強大。(國際化處理、事件傳遞、Bean自動裝配、各種不同應用層的Context實現)。當配置文件被加載,就進行對象實例化。
ClassPathXmlApplicationContext 用於加載classpath(類路徑、src)下的xml
加載xml運行時位置 --> /WEB-INF/classes/...xml
FileSystemXmlApplicationContext 用於加載指定盤符下的xml
加載xml運行時位置 --> /WEB-INF/...xml
通過java web ServletContext.getRealPath() 獲得具體盤符
@Test public void demo02(){ //使用BeanFactory --第一次條用getBean實例化 String xmlPath = "com/zqy/b_di/beans.xml";
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(xmlPath));
BookService bookService = (BookService) beanFactory.getBean("bookServiceId");
bookService.addBook();
} |
5 裝配Bean 基於XML
5.1 實例化方式
l 3種bean實例化方式:默認構造、靜態工廠、實例工廠
l
5.1.1 默認構造
<bean id="" class=""> 必須提供默認構造 |
5.1.2 靜態工廠
l 常用與spring整合其他框架(工具)
l 靜態工廠:用於生成實例對象,所有的方法必須是static
<bean id="" class="工廠全限定類名" factory-method="靜態方法"> |
5.1.2.1 工廠
public class MyBeanFactory {
/** * 創建實例 * @return */ public static UserService createService(){ return new UserServiceImpl(); } } |
5.1.2.2 spring配置
<!-- 將靜態工廠創建的實例交予spring class 確定靜態工廠全限定類名 factory-method 確定靜態方法名 --> <bean id="userServiceId" class="com.zqy.c_inject.b_static_factory.MyBeanFactory" factory-method="createService"></bean> |
5.1.3 實例工廠
l 實例工廠:必須先有工廠實例對象,通過實例對象創建對象。提供所有的方法都是“非靜態”的。
5.1.3.1 工廠
/** * 實例工廠,所有方法非靜態 * */ public class MyBeanFactory {
/** * 創建實例 * @return */ public UserService createService(){ return new UserServiceImpl(); }
} |
5.1.3.2 spring配置
<!-- 創建工廠實例 --> <bean id="myBeanFactoryId" class="com.zqy.c_inject.c_factory.MyBeanFactory"></bean> <!-- 獲得userservice * factory-bean 確定工廠實例 * factory-method 確定普通方法 --> <bean id="userServiceId" factory-bean="myBeanFactoryId" factory-method="createService"></bean>
|
5.2 Bean種類
l 普通bean:之前操作的都是普通bean。<bean id="" class="A"> ,spring直接創建A實例,並返回
l FactoryBean:是一個特殊的bean,具有工廠生成對象能力,只能生成特定的對象。
bean必須使用 FactoryBean接口,此接口提供方法 getObject() 用於獲得特定bean。
<bean id="" class="FB"> 先創建FB實例,使用調用getObject()方法,並返回方法的返回值
FB fb = new FB();
return fb.getObject();
l BeanFactory 和 FactoryBean 對比?
BeanFactory:工廠,用於生成任意bean。
FactoryBean:特殊bean,用於生成另一個特定的bean。例如:ProxyFactoryBean ,此工廠bean用於生產代理。<bean id="" class="....ProxyFactoryBean"> 獲得代理對象實例。AOP使用
5.3 作用域
l 作用域:用於確定spring創建bean實例個數
l 取值:
singleton 單例,默認值。
prototype 多例,每執行一次getBean將獲得一個實例。例如:struts整合spring,配置action多例。
l 配置信息
<bean id="" class="" scope=""> |
<bean id="userServiceId" class="com.zqy.d_scope.UserServiceImpl" scope="prototype" ></bean> |
5.4 生命周期
5.4.1 初始化和銷毀
l 目標方法執行前后執行后,將進行初始化或銷毀。
<bean id="" class="" init-method="初始化方法名稱" destroy-method="銷毀的方法名稱"> |
5.4.1.1 目標類
public class UserServiceImpl implements UserService {
@Override public void addUser() { System.out.println("e_lifecycle add user"); }
public void myInit(){ System.out.println("初始化"); } public void myDestroy(){ System.out.println("銷毀"); }
} |
5.4.1.2 spring配置
<!-- init-method 用於配置初始化方法,准備數據等 destroy-method 用於配置銷毀方法,清理資源等 --> <bean id="userServiceId" class="com.zqy.e_lifecycle.UserServiceImpl" init-method="myInit" destroy-method="myDestroy" ></bean> |
5.4.1.3 測試
@Test public void demo02() throws Exception{ //spring 工廠 String xmlPath = "com/zqy/e_lifecycle/beans.xml"; ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); UserService userService = (UserService) applicationContext.getBean("userServiceId"); userService.addUser();
//要求:1.容器必須close,銷毀方法執行; 2.必須是單例的 // applicationContext.getClass().getMethod("close").invoke(applicationContext); // * 此方法接口中沒有定義,實現類提供 applicationContext.close();
} |
5.4.2 BeanPostProcessor 后處理Bean
l spring 提供一種機制,只要實現此接口BeanPostProcessor,並將實現類提供給spring容器,spring容器將自動執行,在初始化方法前執行before(),在初始化方法后執行after() 。 配置<bean class="">
l Factory hook(勾子) that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.
l spring提供工廠勾子,用於修改實例對象,可以生成代理對象,是AOP底層。
模擬
A a =new A();
a = B.before(a) --> 將a的實例對象傳遞給后處理bean,可以生成代理對象並返回。
a.init();
a = B.after(a);
a.addUser(); //生成代理對象,目的在目標方法前后執行(例如:開啟事務、提交事務)
a.destroy()
5.4.2.1 編寫實現類
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("前方法 : " + beanName); return bean; }
@Override public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException { System.out.println("后方法 : " + beanName); // bean 目標對象 // 生成 jdk 代理 return Proxy.newProxyInstance( MyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("------開啟事務");
//執行目標方法 Object obj = method.invoke(bean, args);
System.out.println("------提交事務"); return obj; }}); } } |
5.4.2.2 配置
<!-- 將后處理的實現類注冊給spring --> <bean class="com.zqy.e_lifecycle.MyBeanPostProcessor"></bean> |
l 問題1:后處理bean作用某一個目標類,還是所有目標類?
所有
l 問題2:如何只作用一個?
通過“參數2”beanName進行控制
5.5 屬性依賴注入
l 依賴注入方式:手動裝配 和 自動裝配
l 手動裝配:一般進行配置信息都采用手動
基於xml裝配:構造方法、setter方法
基於注解裝配:
l 自動裝配:struts和spring 整合可以自動裝配
byType:按類型裝配
byName:按名稱裝配
constructor構造裝配,
auto: 不確定裝配。
5.5.1 構造方法
5.5.1.1 目標類
public class User {
private Integer uid; private String username; private Integer age;
public User(Integer uid, String username) { super(); this.uid = uid; this.username = username; }
public User(String username, Integer age) { super(); this.username = username; this.age = age; }
|
5.5.1.2 spring配置
<!-- 構造方法注入 * <constructor-arg> 用於配置構造方法一個參數argument name :參數的名稱 value:設置普通數據 ref:引用數據,一般是另一個bean id值
index :參數的索引號,從0開始 。如果只有索引,匹配到了多個構造方法時,默認使用第一個。 type :確定參數類型 例如:使用名稱name <constructor-arg name="username" value="jack"></constructor-arg> <constructor-arg name="age" value="18"></constructor-arg> 例如2:【類型type 和 索引 index】 <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg> <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg> --> <bean id="userId" class="com.zqy.f_xml.a_constructor.User" > <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg> <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg> </bean> |
5.5.2 setter方法
<!-- setter方法注入 * 普通數據 <property name="" value="值"> 等效 <property name=""> <value>值 * 引用數據 <property name="" ref="另一個bean"> 等效 <property name=""> <ref bean="另一個bean"/>
--> <bean id="personId" class="com.zqy.f_xml.b_setter.Person"> <property name="pname" value="陽志"></property> <property name="age"> <value>1234</value> </property>
<property name="homeAddr" ref="homeAddrId"></property> <property name="companyAddr"> <ref bean="companyAddrId"/> </property> </bean>
<bean id="homeAddrId" class="com.zqy.f_xml.b_setter.Address"> <property name="addr" value="阜南"></property> <property name="tel" value="911"></property> </bean> <bean id="companyAddrId" class="com.zqy.f_xml.b_setter.Address"> <property name="addr" value="北京八寶山"></property> <property name="tel" value="120"></property> </bean> |
5.5.3 P命令空間[了解]
l 對“setter方法注入”進行簡化,替換<property name="屬性名">,而是在
<bean p:屬性名="普通值" p:屬性名-ref="引用值">
l p命名空間使用前提,必須添加命名空間
<bean id="personId" class="com.zqy.f_xml.c_p.Person" p:pname="禹太璞" p:age="22" p:homeAddr-ref="homeAddrId" p:companyAddr-ref="companyAddrId"> </bean>
<bean id="homeAddrId" class="com.zqy.f_xml.c_p.Address" p:addr="DG" p:tel="東莞"> </bean> <bean id="companyAddrId" class="com.zqy.f_xml.c_p.Address" p:addr="DG" p:tel="島國"> </bean> |
5.5.4 集合注入
<!-- 集合的注入都是給<property>添加子標簽 數組:<array> List:<list> Set:<set> Map:<map> ,map存放k/v 鍵值對,使用<entry>描述 Properties:<props> <prop key=""></prop> 【】
普通數據:<value> 引用數據:<ref> --> <bean id="collDataId" class="com.zqy.f_xml.e_coll.CollData" > <property name="arrayData"> <array> <value>DS</value> <value>DZD</value> <value>屌絲</value> <value>屌中屌</value> </array> </property>
<property name="listData"> <list> <value>於嵩楠</value> <value>曾衛</value> <value>楊煜</value> <value>曾小賢</value> </list> </property>
<property name="setData"> <set> <value>H封</value> <value>J紙</value> <value>A系</value> </set> </property>
<property name="mapData"> <map> <entry key="jack" value="傑克"></entry> <entry> <key><value>rose</value></key> <value>肉絲</value> </entry> </map> </property>
<property name="propsData"> <props> <prop key="高富帥">ASD</prop> <prop key="白富美">AS</prop> <prop key="男屌絲">GG</prop> </props> </property> </bean> |
6 裝配Bean 基於注解
l 注解:就是一個類,使用@注解名稱
l 開發中:使用注解 取代 xml配置文件。
1. @Component取代<bean class="">
@Component("id") 取代 <bean id="" class="">
2.web開發,提供3個@Component注解衍生注解(功能一樣)取代<bean class="">
@Repository :dao層
@Service:service層
@Controller:web層
3.依賴注入 ,給私有字段設置,也可以給setter方法設置
普通值:@Value("")
引用值:
方式1:按照【類型】注入
@Autowired
方式2:按照【名稱】注入1
@Autowired
@Qualifier("名稱")
方式3:按照【名稱】注入2
@Resource("名稱")
4.生命周期
初始化:@PostConstruct
銷毀:@PreDestroy
5.作用域
@Scope("prototype") 多例
l 注解使用前提,添加命名空間,讓spring掃描含有注解類
<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 base-package="com.zqy.g_annotation.a_ioc"></context:component-scan> </beans> |