---恢復內容開始---html
1 spring框架概述java
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(一站式) 輕量級開源框架。web
l 輕量級:與EJB對比,依賴資源少,銷燬的資源少。spring
l 分層: 一站式,每個層都提供的解決方案express
web層:struts,spring-MVC編程
service層:springapi
dao層:hibernate,mybatis , jdbcTemplate --> spring-data數組
1.2 spring核心服務器
Spring的核心是控制反轉(IoC)和面向切面(AOP)mybatis
IoC(Inversion of control): 控制反轉控制權由對象自己轉向容器;由容器根據配置文件去建立實例並建立各個實例之間的依賴關係
AOP(Aspect Oriented Programming),也就是面向方面編程的技術。AOP基於IoC基礎,是對OOP的有益補充。
1.3spring優勢
l 方便解耦,簡化開發 (高內聚低耦合)
l AOP編程的支持
l 聲明式事務的支持
l 方便程序的測試
l 方便集成各類優秀框架
l 下降JavaEE API的使用難度
|
核心容器:beans、core、context、expression
l 4 + 1 : 4個核心(beans、core、context、expression) + 1個依賴(commons-loggins...jar)
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"); }
} |
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> |
@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();
} |
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>
l 建立BookService接口和實現類
l 建立BookDao接口和實現類
l 將dao和service配置 xml文件
l 使用api測試
public interface BookDao {
public void addBook();
} |
public class BookDaoImpl implements BookDao {
@Override public void addBook() { System.out.println("di add book"); }
} |
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(); }
} |
<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> |
@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();
} |
l 步驟一:肯定xsd文件位置
spring-framework-3.2.0.RELEASE\schema\beans
l 步驟二:複製路徑
l 步驟三:搜索「xml catalog」
l 步驟四:添加約束提示
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();
} |
l 3種bean實例化方式:默認構造、靜態工廠、實例工廠
l
<bean id="" class=""> 必須提供默認構造 |
l 經常使用與spring整合其餘框架(工具)
l 靜態工廠:用於生成實例對象,全部的方法必須是static
<bean id="" class="工廠全限定類名" factory-method="靜態方法"> |
public class MyBeanFactory {
/** * 建立實例 * @return */ public static UserService createService(){ return new UserServiceImpl(); } } |
<!-- 將靜態工廠建立的實例交予spring class 肯定靜態工廠全限定類名 factory-method 肯定靜態方法名 --> <bean id="userServiceId" class="com.zqy.c_inject.b_static_factory.MyBeanFactory" factory-method="createService"></bean> |
l 實例工廠:必須先有工廠實例對象,經過實例對象建立對象。提供全部的方法都是「非靜態」的。
/** * 實例工廠,全部方法非靜態 * */ public class MyBeanFactory {
/** * 建立實例 * @return */ public UserService createService(){ return new UserServiceImpl(); }
} |
<!-- 建立工廠實例 --> <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>
|
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使用
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> |
l 目標方法執行先後執行後,將進行初始化或銷燬。
<bean id="" class="" init-method="初始化方法名稱" destroy-method="銷燬的方法名稱"> |
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("銷燬"); }
} |
<!-- init-method 用於配置初始化方法,準備數據等 destroy-method 用於配置銷燬方法,清理資源等 --> <bean id="userServiceId" class="com.zqy.e_lifecycle.UserServiceImpl" init-method="myInit" destroy-method="myDestroy" ></bean> |
@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();
} |
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()
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; }}); } } |
<!-- 將後處理的實現類註冊給spring --> <bean class="com.zqy.e_lifecycle.MyBeanPostProcessor"></bean> |
l 問題1:後處理bean做用某一個目標類,仍是全部目標類?
全部
l 問題2:如何只做用一個?
經過「參數2」beanName進行控制
l 依賴注入方式:手動裝配 和 自動裝配
l 手動裝配:通常進行配置信息都採用手動
基於xml裝配:構造方法、setter方法
基於註解裝配:
l 自動裝配:struts和spring 整合能夠自動裝配
byType:按類型裝配
byName:按名稱裝配
constructor構造裝配,
auto: 不肯定裝配。
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; }
|
<!-- 構造方法注入 * <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> |
<!-- 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> |
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> |
<!-- 集合的注入都是給<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> |
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> |