1 spring框架概述
1.1 什么是spring
- Spring是一個開源框架慷荔,Spring是于2003 年興起的一個輕量級的Java 開發(fā)框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中闡述的部分理念和原型衍生而來。它是為了解決企業(yè)應(yīng)用開發(fā)的復雜性而創(chuàng)建的』炭矗框架的主要優(yōu)勢之一就是其分層架構(gòu),分層架構(gòu)允許使用者選擇使用哪一個組件六孵,同時為 J2EE 應(yīng)用程序開發(fā)提供集成的框架纬黎。Spring使用基本的JavaBean來完成以前只可能由EJB完成的事情。然而狸臣,Spring的用途不僅限于服務(wù)器端的開發(fā)莹桅。從簡單性、可測試性和松耦合的角度而言烛亦,任何Java應(yīng)用都可以從Spring中受益诈泼。Spring的核心是控制反轉(zhuǎn)(IoC)和面向切面(AOP)。簡單來說煤禽,Spring是一個分層的JavaSE/EE full-stack(一站式) 輕量級開源框架铐达。
- 輕量級:與EJB對比,依賴資源少檬果,銷毀的資源少瓮孙。
- 分層: 一站式,每一個層都提供的解決方案
web層:struts选脊,spring-MVC
service層:spring
dao層:hibernate杭抠,mybatis , jdbcTemplate --> spring-data
1.2 spring由來
- Expert One-to-One J2EE Design and Development
- Expert One-to-One J2EE Development without EJB
1.3 spring核心
- Spring的核心是控制反轉(zhuǎn)(IoC)和面向切面(AOP)
1.4 spring優(yōu)點
- 方便解耦恳啥,簡化開發(fā) (高內(nèi)聚低耦合)
? Spring就是一個大工廠(容器)偏灿,可以將所有對象創(chuàng)建和依賴關(guān)系維護,交給Spring管理
? spring工廠是用于生成bean - AOP編程的支持
? Spring提供面向切面編程钝的,可以方便的實現(xiàn)對程序進行權(quán)限攔截翁垂、運行監(jiān)控等功能 - 聲明式事務(wù)的支持
? 只需要通過配置就可以完成對事務(wù)的管理铆遭,而無需手動編程 - 方便程序的測試
? Spring對Junit4支持,可以通過注解方便的測試Spring程序 - 方便集成各種優(yōu)秀框架
? Spring不排斥各種優(yōu)秀的開源框架沿猜,其內(nèi)部提供了對各種優(yōu)秀框架(如:Struts枚荣、Hibernate、MyBatis啼肩、Quartz等)的直接支持 - 降低JavaEE API的使用難度
? Spring 對JavaEE開發(fā)中非常難用的一些API(JDBC橄妆、JavaMail、遠程調(diào)用等)祈坠,都提供了封裝呼畸,使這些API應(yīng)用難度大大降低
1.5 spring體系結(jié)構(gòu)
核心容器:beans、core颁虐、context、expression
2 入門案例:IoC【掌握】
2.1 導入jar包
- 4 + 1 : 4個核心(beans卧须、core另绩、context、expression) + 1個依賴(commons-loggins...jar)
2.2 目標類
- 提供UserService接口和實現(xiàn)類
- 獲得UserService實現(xiàn)類的實例
之前開發(fā)中花嘶,直接new一個對象即可笋籽。
學習spring之后,將由Spring創(chuàng)建對象實例--> IoC 控制反轉(zhuǎn)(Inverse of Control)
之后需要實例對象時椭员,從spring工廠(容器)中獲得车海,需要將實現(xiàn)類的全限定名稱配置到xml文件中
public interface UserService {
public void addUser();
}
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("a_ico add user");
}
}
2.3 配置文件
- 位置:任意,開發(fā)中一般在classpath下(src)
- 名稱:任意隘击,開發(fā)中常用applicationContext.xml
- 內(nèi)容:添加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> 配置需要創(chuàng)建的對象
id :用于之后從spring容器獲得實例時使用的
class :需要創(chuàng)建實例的全限定類名
-->
<bean id="userServiceId" class="com.itheima.a_ioc.UserServiceImpl"></bean>
</beans>
2.4 測試
@Test
public void demo02(){
//從spring容器獲得
//1 獲得容器
String xmlPath = "com/itheima/a_ioc/beans.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
//2獲得內(nèi)容 --不需要自己new侍芝,都是從spring容器獲得
UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
}
3 入門案例:DI【掌握】
- DI Dependency Injection ,依賴注入
is a :是一個,繼承埋同。
has a:有一個州叠,成員變量,依賴凶赁。
class B {
private A a; //B類依賴A類
}
依賴:一個對象需要使用另一個對象
注入:通過setter方法進行另一個對象實例設(shè)置咧栗。
- 例如:
class BookServiceImpl{
//之前開發(fā):接口 = 實現(xiàn)類 (service和dao耦合)
//private BookDao bookDao = new BookDaoImpl();
//spring之后 (解耦:service實現(xiàn)類使用dao接口,不知道具體的實現(xiàn)類)
private BookDao bookDao;
setter方法
}
模擬spring執(zhí)行過程
創(chuàng)建service實例:BookService bookService = new BookServiceImpl() -->IoC <bean>
創(chuàng)建dao實例:BookDao bookDao = new BookDaoImple() -->IoC
將dao設(shè)置給service:bookService.setBookDao(bookDao); -->DI <property>
3.1 目標類
- 創(chuàng)建BookService接口和實現(xiàn)類
- 創(chuàng)建BookDao接口和實現(xiàn)類
- 將dao和service配置 xml文件
- 使用api測試
3.1.1 dao
public interface BookDao {
public void addBook();
}
public class BookDaoImpl implements BookDao {
@Override
public void addBook() {
System.out.println("di add book");
}
}
3.1.2 service
public interface BookService {
public abstract void addBook();
}
public class BookServiceImpl implements BookService {
// 方式1:之前虱肄,接口=實現(xiàn)類
// 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();
}
}
3.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執(zhí)行過程
創(chuàng)建service實例:BookService bookService = new BookServiceImpl() IoC <bean>
創(chuàng)建dao實例:BookDao bookDao = new BookDaoImpl() IoC
將dao設(shè)置給service:bookService.setBookDao(bookDao); DI <property>
<property> 用于進行屬性注入
name: bean的屬性名致板,通過setter方法獲得
setBookDao ##> BookDao ##> bookDao
ref :另一個bean的id值的引用
-->
<!-- 創(chuàng)建service -->
<bean id="bookServiceId" class="com.itheima.b_di.BookServiceImpl">
<property name="bookDao" ref="bookDaoId"></property>
</bean>
<!-- 創(chuàng)建dao實例 -->
<bean id="bookDaoId" class="com.itheima.b_di.BookDaoImpl"></bean>
</beans>
3.3 測試
@Test
public void demo01(){
//從spring容器獲得
String xmlPath = "com/itheima/b_di/beans.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
BookService bookService = (BookService) applicationContext.getBean("bookServiceId");
bookService.addBook();
}
4 myeclipse schema xml提示
-
步驟一:確定xsd文件位置
spring-framework-3.2.0.RELEASE\schema\beans
步驟二:復制路徑
- 步驟三:搜索“xml catalog”
- 步驟四:添加約束提示
5 核心API
- api整體了解,之后不使用咏窿,在學習過程需要斟或。
- BeanFactory :這是一個工廠,用于生成任意bean翰灾。
采取延遲加載缕粹,第一次getBean時才會初始化Bean - ApplicationContext:是BeanFactory的子接口稚茅,功能更強大。(國際化處理平斩、事件傳遞亚享、Bean自動裝配、各種不同應(yīng)用層的Context實現(xiàn))绘面。當配置文件被加載欺税,就進行對象實例化。
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/itheima/b_di/beans.xml";
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(xmlPath));
BookService bookService = (BookService) beanFactory.getBean("bookServiceId");
bookService.addBook();
}
6 裝配Bean 基于XML
6.1 實例化方式
- 3種bean實例化方式:默認構(gòu)造晚凿、靜態(tài)工廠、實例工廠
6.1.1 默認構(gòu)造
<bean id="" class=""> 必須提供默認構(gòu)造
6.1.2 靜態(tài)工廠
- 常用與spring整合其他框架(工具)
- 靜態(tài)工廠:用于生成實例對象瘦馍,所有的方法必須是static
<bean id="" class="工廠全限定類名" factory-method="靜態(tài)方法">
6.1.2.1 工廠
public class MyBeanFactory {
/**
* 創(chuàng)建實例
* @return
*/
public static UserService createService(){
return new UserServiceImpl();
}
}
6.1.2.2 spring配置
<!-- 將靜態(tài)工廠創(chuàng)建的實例交予spring
class 確定靜態(tài)工廠全限定類名
factory-method 確定靜態(tài)方法名
-->
<bean id="userServiceId" class="com.itheima.c_inject.b_static_factory.MyBeanFactory"
factory-method="createService"></bean>
6.1.3 實例工廠
- 實例工廠:必須先有工廠實例對象歼秽,通過實例對象創(chuàng)建對象。提供所有的方法都是“非靜態(tài)”的情组。
6.1.3.1 工廠
/**
* 實例工廠,所有方法非靜態(tài)
*
*/
public class MyBeanFactory {
/**
* 創(chuàng)建實例
* @return
*/
public UserService createService(){
return new UserServiceImpl();
}
}
6.1.3.2 spring配置
<!-- 創(chuàng)建工廠實例 -->
<bean id="myBeanFactoryId" class="com.itheima.c_inject.c_factory.MyBeanFactory"></bean>
<!-- 獲得userservice
* factory-bean 確定工廠實例
* factory-method 確定普通方法
-->
<bean id="userServiceId" factory-bean="myBeanFactoryId" factory-method="createService"></bean>
6.2 Bean種類
- 普通bean:之前操作的都是普通bean燥筷。<bean id="" class="A"> ,spring直接創(chuàng)建A實例院崇,并返回
- FactoryBean:是一個特殊的bean肆氓,具有工廠生成對象能力,只能生成特定的對象底瓣。
bean必須使用 FactoryBean接口谢揪,此接口提供方法 getObject() 用于獲得特定bean。
<bean id="" class="FB"> 先創(chuàng)建FB實例捐凭,使用調(diào)用getObject()方法拨扶,并返回方法的返回值
FB fb = new FB();
return fb.getObject(); - BeanFactory 和 FactoryBean 對比?
BeanFactory:工廠柑营,用于生成任意bean屈雄。
FactoryBean:特殊bean,用于生成另一個特定的bean官套。例如:ProxyFactoryBean 酒奶,此工廠bean用于生產(chǎn)代理。<bean id="" class="....ProxyFactoryBean"> 獲得代理對象實例奶赔。AOP使用
6.3 作用域
- 作用域:用于確定spring創(chuàng)建bean實例個數(shù)
- 取值:
singleton 單例惋嚎,默認值。
prototype 多例站刑,每執(zhí)行一次getBean將獲得一個實例另伍。例如:struts整合spring,配置action多例。 -
配置信息
<bean id="" class="" scope="">
<bean id="userServiceId" class="com.itheima.d_scope.UserServiceImpl"
scope="prototype" ></bean>
6.4 生命周期
6.4.1 初始化和銷毀
- 目標方法執(zhí)行前后執(zhí)行后摆尝,將進行初始化或銷毀温艇。
<bean id="" class="" init-method="初始化方法名稱" destroy-method="銷毀的方法名稱">
6.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("銷毀");
}
}
6.4.1.2 spring配置
<!--
init-method 用于配置初始化方法,準備數(shù)據(jù)等
destroy-method 用于配置銷毀方法,清理資源等
-->
<bean id="userServiceId" class="com.itheima.e_lifecycle.UserServiceImpl"
init-method="myInit" destroy-method="myDestroy" ></bean>
6.4.1.3 測試
@Test
public void demo02() throws Exception{
//spring 工廠
String xmlPath = "com/itheima/e_lifecycle/beans.xml";
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
//要求:1.容器必須close,銷毀方法執(zhí)行; 2.必須是單例的
// applicationContext.getClass().getMethod("close").invoke(applicationContext);
// * 此方法接口中沒有定義堕汞,實現(xiàn)類提供
applicationContext.close();
}
6.4.2 BeanPostProcessor 后處理Bean
- spring 提供一種機制勺爱,只要實現(xiàn)此接口BeanPostProcessor,并將實現(xiàn)類提供給spring容器讯检,spring容器將自動執(zhí)行琐鲁,在初始化方法前執(zhí)行before(),在初始化方法后執(zhí)行after() 人灼。 配置<bean class="">
- Factory hook(勾子) that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.
- spring提供工廠勾子围段,用于修改實例對象,可以生成代理對象投放,是AOP底層奈泪。
模擬
A a =new A();
a = B.before(a) --> 將a的實例對象傳遞給后處理bean,可以生成代理對象并返回灸芳。
a.init();
a = B.after(a);
a.addUser(); //生成代理對象段磨,目的在目標方法前后執(zhí)行(例如:開啟事務(wù)、提交事務(wù))
a.destroy()
6.4.2.1 編寫實現(xiàn)類
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("------開啟事務(wù)");
//執(zhí)行目標方法
Object obj = method.invoke(bean, args);
System.out.println("------提交事務(wù)");
return obj;
}});
}
}
6.4.2.2 配置
<!-- 將后處理的實現(xiàn)類注冊給spring -->
<bean class="com.itheima.e_lifecycle.MyBeanPostProcessor"></bean>
- 問題1:后處理bean作用某一個目標類耗绿,還是所有目標類?
所有 - 問題2:如何只作用一個砾隅?
通過“參數(shù)2”beanName進行控制
6.5 屬性依賴注入
- 依賴注入方式:手動裝配 和 自動裝配
- 手動裝配:一般進行配置信息都采用手動
基于xml裝配:構(gòu)造方法误阻、setter方法
基于注解裝配: - 自動裝配:struts和spring 整合可以自動裝配
byType:按類型裝配
byName:按名稱裝配
constructor構(gòu)造裝配,
auto: 不確定裝配晴埂。
6.5.1 構(gòu)造方法
6.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;
}
6.5.1.2 spring配置
<!-- 構(gòu)造方法注入
* <constructor-arg> 用于配置構(gòu)造方法一個參數(shù)argument
name :參數(shù)的名稱
value:設(shè)置普通數(shù)據(jù)
ref:引用數(shù)據(jù)究反,一般是另一個bean id值
index :參數(shù)的索引號,從0開始 儒洛。如果只有索引精耐,匹配到了多個構(gòu)造方法時,默認使用第一個琅锻。
type :確定參數(shù)類型
例如:使用名稱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.itheima.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>
6.5.2 setter方法
<!-- setter方法注入
* 普通數(shù)據(jù)
<property name="" value="值">
等效
<property name="">
<value>值
* 引用數(shù)據(jù)
<property name="" ref="另一個bean">
等效
<property name="">
<ref bean="另一個bean"/>
-->
<bean id="personId" class="com.itheima.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.itheima.f_xml.b_setter.Address">
<property name="addr" value="阜南"></property>
<property name="tel" value="911"></property>
</bean>
<bean id="companyAddrId" class="com.itheima.f_xml.b_setter.Address">
<property name="addr" value="北京八寶山"></property>
<property name="tel" value="120"></property>
</bean>
6.5.3 P命令空間[了解]
- 對“setter方法注入”進行簡化卦停,替換<property name="屬性名">,而是在
<bean p:屬性名="普通值" p:屬性名-ref="引用值"> - p命名空間使用前提恼蓬,必須添加命名空間
<bean id="personId" class="com.itheima.f_xml.c_p.Person"
p:pname="禹太璞" 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="DG" p:tel="東莞">
</bean>
<bean id="companyAddrId" class="com.itheima.f_xml.c_p.Address"
p:addr="DG" p:tel="島國">
</bean>
6.5.4 SpEL[了解]
- 對<property>進行統(tǒng)一編程惊完,所有的內(nèi)容都使用value
<property name="" value="#{表達式}">
#{123}、#{'jack'} : 數(shù)字处硬、字符串
#{beanId} :另一個bean引用
#{beanId.propName} :操作數(shù)據(jù)
#{beanId.toString()} :執(zhí)行方法
#{T(類).字段|方法} :靜態(tài)方法或字段
<!--
<property name="cname" value="#{'jack'}"></property>
<property name="cname" value="#{customerId.cname.toUpperCase()}"></property>
通過另一個bean小槐,獲得屬性,調(diào)用的方法
<property name="cname" value="#{customerId.cname?.toUpperCase()}"></property>
?. 如果對象不為null荷辕,將調(diào)用方法
-->
<bean id="customerId" class="com.itheima.f_xml.d_spel.Customer" >
<property name="cname" value="#{customerId.cname?.toUpperCase()}"></property>
<property name="pi" value="#{T(java.lang.Math).PI}"></property>
</bean>
6.5.5 集合注入
<!--
集合的注入都是給<property>添加子標簽
數(shù)組:<array>
List:<list>
Set:<set>
Map:<map> 凿跳,map存放k/v 鍵值對件豌,使用<entry>描述
Properties:<props> <prop key=""></prop> 【】
普通數(shù)據(jù):<value>
引用數(shù)據(jù):<ref>
-->
<bean id="collDataId" class="com.itheima.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>曾衛(wèi)</value>
<value>楊煜</value>
<value>曾小賢</value>
</list>
</property>
<property name="setData">
<set>
<value>停封</value>
<value>薄紙</value>
<value>關(guān)系</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="高富帥">嫐</prop>
<prop key="白富美">嬲</prop>
<prop key="男屌絲">挊</prop>
</props>
</property>
</bean>
7 裝配Bean 基于注解
- 注解:就是一個類,使用@注解名稱
- 開發(fā)中:使用注解 取代 xml配置文件控嗜。
1. @Component取代<bean class="">
@Component("id") 取代 <bean id="" class="">
2.web開發(fā)茧彤,提供3個@Component注解衍生注解(功能一樣)取代<bean class="">
@Repository :dao層
@Service:service層
@Controller:web層
3.依賴注入 ,給私有字段設(shè)置躬审,也可以給setter方法設(shè)置
普通值:@Value("")
引用值:
方式1:按照【類型】注入
@Autowired
方式2:按照【名稱】注入1
@Autowired
@Qualifier("名稱")
方式3:按照【名稱】注入2
@Resource("名稱")
4.生命周期
初始化:@PostConstruct
銷毀:@PreDestroy
5.作用域
@Scope("prototype") 多例
-
注解使用前提棘街,添加命名空間,讓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.itheima.g_annotation.a_ioc">
</context:component-scan>
</beans>