spring核心組件總結
spring介紹
spring概念
IOC: Inverse Of Control 控制反轉
將我們創建對象的方式反轉了,以前創建對象是由我們開發人員自己維護,包括依賴注入關系也是自己注入。
使用了spring之后,對象的創建以及依賴關系,由spring完成創建以及注入。
控制反轉就是反轉了對象的創建方式。從我們自己創建反轉給了spring
DI: Dependency Injection 依賴注入
實現ioc思想需要 DI提供支持
注入方式:1)set方式注入 2) 構造方法注入 3) 字段注入(不推薦)
注入類型:1) 值類型注入 2)引用類型注入
AOP 面向切面的編程 (橫向重復,縱向抽取)
舉例:攔截器(身份校驗)、過濾器(編碼處理)、動態代理(事務)
spring aop實現原理
動態代理(優先):被代理對象必須要實現接口,才能產生代理對象.如果沒有接口將不能使用動態代理技術
cglib代理(沒有接口):第三方代理技術,cglib代理.可以對任何類生成代理.代理的原理是對目標對象進行繼承代理. 如果目標對象被final修飾.那么該類無法被cglib代理.
spring名詞解釋
aop依賴所需包
aop代碼演示(xml配置)
//通知類
public class MyAdvice {
//前置通知
// |-目標方法運行之前調用
//后置通知(如果出現異常不會調用)
// |-在目標方法運行之后調用
//環繞通知
// |-在目標方法之前和之后都調用
//異常攔截通知
// |-如果出現異常,就會調用
//后置通知(無論是否出現 異常都會調用)
// |-在目標方法運行之后調用
//----------------------------------------------------------------
//前置通知
public void before(){
System.out.println("這是前置通知");
}
//后置通知
public void afterReturning(){
System.out.println("這是后置通知(出現異常不執行)!!");
}
//環繞通知
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("這是環繞通知之前的部分!");
Object proceed = pjp.proceed();//璋冪敤鐩爣鏂規硶
System.out.println("這是環繞通知之后的部分");
return proceed;
}
//異常通知
public void afterException(){
System.out.println("這是異常通知,出現異常執行!");
}
//后置通知
public void after(){
System.out.println("這是后置通知(出現異常也會調用)!!");
}
}
<!-- 1.配置目標對象 -->
<bean name="userService" class="com.yoci.service.UserServiceImpl"></bean>
<!-- 2.配置通知對象 -->
<bean name="myAdvice" class="com.yoci.springaop.MyAdvice"></bean>
<!-- 3.配置將通知織入目標對象 -->
<aop:config>
<!-- 配置切入點
public void cn.itcast.service.UserServiceImpl.save()
void cn.itcast.service.UserServiceImpl.save()
* cn.itcast.service.UserServiceImpl.save()
* cn.itcast.service.UserServiceImpl.*()
* cn.itcast.service.*ServiceImpl.*(..)
* cn.itcast.service..*ServiceImpl.*(..)
-->
<aop:pointcut expression="execution(* com.yoci.service.*ServiceImpl.*(..))" id="pc"/>
<aop:aspect ref="myAdvice">
<!-- 指定名為before方法作為前置通知 -->
<aop:before method="before" pointcut-ref="pc"/>
<!-- 后置 -->
<aop:after-returning method="afterReturning" pointcut-ref="pc" />
<!-- 環繞通知 -->
<aop:around method="around" pointcut-ref="pc"/>
<!-- 異常攔截通知 -->
<aop:after-throwing method="afterException" pointcut-ref="pc"/>
<!-- 后置 -->
<aop:after method="after" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
aop代碼演示(注解配置)
//通知類
@Aspect
public class MyAdvice {
@Pointcut("execution(* com.yoci.service.*ServiceImpl.*(..))")
public void pointcut(){}
@Before("MyAdvice.pointcut()")
public void before(){
System.out.println("這是前置通知");
}
@AfterReturning("execution(* com.yoci.service.*ServiceImpl.*(..))")
public void afterReturning(){
System.out.println("這是后置通知(出現異常不執行)!!");
}
@Around("execution(* com.yoci.service.*ServiceImpl.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("這是環繞通知之前的部分!");
Object proceed = pjp.proceed();//調用目標方法
System.out.println("這是環繞通知之后的部分");
return proceed;
}
@AfterThrowing("execution(* com.yoci.service.*ServiceImpl.*(..))")
public void afterException(){
System.out.println("這是異常通知,出現異常執行!");
}
@After("execution(* com.yoci.service.*ServiceImpl.*(..))")
public void after(){
System.out.println("這是后置通知(出現異常也會調用)!!");
}
}
<!-- 1.配置目標對象 -->
<bean name="userService" class="com.yoci.service.UserServiceImpl"></bean>
<!-- 2.配置通知對象 -->
<bean name="myAdvice" class="com.yoci.annotationaop.MyAdvice"></bean>
<!-- 3.開啟使用注解完成織入 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
spring 中的工廠(容器)
ApplicationContext接口由兩個實現類:
1) ClassPathXmlApplicationContext: 加載類路徑下的spring的配置
2)FilesSystemXmlApplicationContext:加載本地磁盤下的spring的配置
BeanFactrory(過時)
BeanFactory和ApplicationContext的區別:
1)BeanFactory:是在getBean的時候才會生成類的實例
2)ApplicationContext:是在加載applicationContext.xml(容器啟動)時就會創建
spring配置詳解
Bean元素
<!-- 將User對象交給spring容器管理 -->
<!-- Bean元素:使用該元素描述需要spring容器管理的對象
class屬性:被管理對象的完整類名.
name屬性:給被管理的對象起個名字.獲得對象時根據該名稱獲得對象.
可以重復.可以使用特殊字符.
id屬性: 與name屬性一模一樣.
名稱不可重復.不能使用特殊字符.
結論: 盡量使用name屬性.
-->
<bean name="user" class="cn.itcast.bean.User" ></bean>
<!-- 導入其他spring配置文件 -->
<!-- 分模塊配置 -->
<import resource="cn/itcast/b_create/applicationContext.xml"/>
Bean元素進階
scope屬性(作用域)
1)singleton(默認值):單例對象.被標識為單例的對象在spring容器中只會存在一個實例
2)prototype:多例原型.被標識為多例的對象,每次再獲得才會創建.每次創建都是新的對象.整合struts2時,ActionBean必須配置為多例的.
3)request:web環境下.對象與request生命周期一致.
4)session:web環境下,對象與session生命周期一致.
5)global-session:global-session和Portlet應用相關。當你的應用部署在Portlet容器中工作時,它包含很多portlet。如果你想要聲明讓所有的portlet共用全局的存儲變量的話,那么這全局變量需要存儲在global-session中。
生命周期屬性
1)init-method:配置一個方法作為生命周期初始化方法.spring會在對象創建之后立即調用.
2)destory-method:配置一個方法作為生命周期的銷毀方法.spring容器在關閉並銷毀所有容器中的對象之前調用.
<bean name="user" class="cn.itcast.bean.User"
init-method="init" destroy-method="destory" ></bean>
public class User {
private String name;
private Integer age;
private Car car;
public Car getCar() {return car;}
public void setCar(Car car) {this.car = car;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public Integer getAge() {return age;}
public void setAge(Integer age) {this.age = age;}
public void init(){
System.out.println("我是初始化方法!");
}
public void destory(){
System.out.println("我是銷毀方法!");
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
}
}
spring創建對象的方式
1)空參構造方式
2)靜態工廠(了解)
3)實例工廠(了解)
<!-- 創建方式1:空參構造創建 -->
<bean name="user" class="cn.itcast.bean.User"
init-method="init" destroy-method="destory" ></bean>
<!-- 創建方式2:靜態工廠創建
調用UserFactory的createUser方法創建名為user2的對象.放入容器
-->
<bean name="user2"
class="cn.itcast.b_create.UserFactory"
factory-method="createUser" ></bean>
<!-- 創建方式3:實例工廠創建
調用UserFactory對象的createUser2方法創建名為user3的對象.放入容器
-->
<bean name="user3"
factory-bean="userFactory"
factory-method="createUser2" ></bean>
<bean name="userFactory"
class="cn.itcast.b_create.UserFactory" ></bean>
public class UserFactory {
public static User createUser(){
System.out.println("靜態工廠創建User");
return new User();
}
public User createUser2(){
System.out.println("實例工廠創建User");
return new User();
}
}
spring屬性注入
<!-- set方式注入: -->
<bean name="user" class="com.yoci.entity.User" >
<!-- 值類型注入 -->
<property name="name" value="zhangsan"></property>
<property name="age" value="22"></property>
<!-- 引用類型注入 -->
<property name="car" ref="car"></property>
</bean>
<!-- 將car對象配置到容器當中 -->
<bean name="car" class="com.yoci.entity.Car">
<property name="name" value="蘭博基尼"></property>
<property name="color" value="黃色"></property>
</bean>
<!-- 構造函數注入 -->
<bean name="user1" class="com.yoci.entity.User">
<!-- name屬性: 構造函數的參數名 -->
<!-- index屬性: 構造函數的參數索引 -->
<!-- type屬性: 構造函數的參數類型-->
<constructor-arg name="name" index="0" value="李四" ></constructor-arg>
<constructor-arg name="car" index="1" ref="car" ></constructor-arg>
</bean>
<!-- p名稱空間注入 -->
<!--
1.導入P名稱空間 xmlns:p="http://www.springframework.org/schema/p"
2.使用p:屬性完成注入
-值類型: p:屬性名="值"
-對象類型: p:屬性名-ref="bean名稱" -->
<bean name="user2" class="com.yoci.entity.User" p:name="wangwu" p:age="26" p:car-ref="car"></bean>
<!-- spEL注入 -->
<bean name="user3" class="com.yoci.entity.User">
<property name="name" value="#{user1.name}"></property>
<property name="age" value="#{user2.age}"></property>
<property name="car" ref="car"></property>
</bean>
<!-- 復雜類型注入 -->
<bean name="collection" class="com.yoci.entity.Collection">
<!-- 如果數組中只准備注入一個值(對象),直接使用value|ref即可
<property name="arr" value="tom" ></property>
-->
<!-- array注入,多個元素注入 -->
<property name="arr">
<array>
<value>tom</value>
<value>jack</value>
<ref bean="user2"></ref>
</array>
</property>
<!--
如果List中只准備注入一個值(對象),直接使用value|ref即可
<property name="list" value="jack" ></property>
-->
<property name="list">
<list>
<value>zhangsan</value>
<value>李四</value>
<ref bean="user"/>
</list>
</property>
<!-- map類型注入 -->
<property name="map">
<map>
<entry key="url" value="www.yoci.com"></entry>
<entry key="user3" value-ref="user"></entry>
</map>
</property>
<!-- prperties 類型注入 -->
<property name="prop">
<props>
<prop key="driverClass">com.jdbc.mysql.Driver</prop>
<prop key="userName">root</prop>
<prop key="password">1234</prop>
</props>
</property>
spring事務
什么是事務:
事務邏輯上的一組操作,組成這組操作的各個邏輯單元,要么一起成功,要么一起失敗。
事務特性
原子性 :強調事務的不可分割.
一致性 :事務的執行的前后數據的完整性保持一致.
隔離性 :一個事務執行的過程中,不應該受到其他事務的干擾
持久性 :事務一旦結束,數據就持久到數據庫
如果不考慮隔離性引發安全性問題:
臟讀 :一個事務讀到了另一個事務的未提交的數據
不可重復讀 :一個事務讀到了另一個事務已經提交的 update 的數據導致多次查詢結果不一致.
虛幻讀 :一個事務讀到了另一個事務已經提交的 insert 的數據導致多次查詢結果不一致.
解決讀問題:設置事務隔離級別
未提交讀 :臟讀,不可重復讀,虛讀都有可能發生
已提交讀 :避免臟讀。但是不可重復讀和虛讀有可能發生
可重復讀 :避免臟讀和不可重復讀.但是虛幻讀有可能發生.
串行化的 :避免以上所有讀問題.
Mysql 默認:可重復讀 Oracle 默認:讀已提交
事務的操作對象
在spring中玩事務管理.最為核心的對象就TransactionManager對象
事務的屬性介紹
事務隔離級別:
1 讀未提交 2 讀已提交 4 可重復讀 8 串行化
是否只讀:
true/false
事務的傳播行為:
spring代碼(xml配置)
<!-- 事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 數據源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 以方法為單位,指定方法應用什么事務屬性
isolation:隔離級別
propagation:傳播行為
read-only:是否只讀
-->
<!-- 傳播行為 -->
<tx:method name="save*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="persist*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="modify*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="delete*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="remove*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="get*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true" />
<tx:method name="find*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true" />
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
</tx:attributes>
</tx:advice>
<!-- 切面 -->
<aop:config>
<aop:advisor advice-ref="txAdvice"
pointcut="execution(* cn.itcast.crm.service.*.*(..))" />
</aop:config>
spring代碼(注解配置)
<!-- 事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 數據源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 開啟使用注解管理aop事務 -->
<tx:annotation-driven/>
@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=true)
public class AccountServiceImpl implements AccountService {
private AccountDao ad ;
private TransactionTemplate tt;
@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)
public void transfer(final Integer from,final Integer to,final Double money) {
//減錢
ad.decreaseMoney(from, money);
int i = 1/0;
//加錢
ad.increaseMoney(to, money);
}
}
spring注解
開啟spring注解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd ">
<!--
引入:
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
-->
<!-- 指定掃描cn.itcast.bean報下的所有類中的注解.
注意:掃描包時.會掃描指定報下的所有子孫包
-->
<context:component-scan base-package="cn.itcast.bean"></context:component-scan>
</beans>
注解使用介紹
@Component("user") = <bean name="user" class="cn.itcast.bean.User" />
// service層
@Service("user")
// web層
@Controller("user")
// dao層
@Repository("user")
//指定對象的作用范圍
@Scope(scopeName="singleton/prototype")
//屬性注入,推薦使用set方法注入方式, 第一種破壞封裝性
@Value("18")
private Integer age;
@Value("tom")
public void setName(String name) {
this.name = name;
}
//自動裝配
@Autowired //問題:如果匹配多個類型一致的對象.將無法選擇具體注入哪一個對象.
@Qualifier("car2")//使用@Qualifier 配合 @Autowired注解告訴spring容器自動裝配哪個名稱的對象
//手動裝配,指定注入哪個名稱的對象
@Resource(name="car")
private Car car;
//在對象被創建后調用.init-method
@PostConstruct
public void init(){
System.out.println("我是初始化方法!");
}
//在銷毀之前調用.destory-method
@PreDestroy
public void destory(){
System.out.println("我是銷毀方法!");
}
spring整合junit測試
導入aop+test包
//幫我們創建容器
@RunWith(SpringJUnit4ClassRunner.class)
//指定創建容器時使用哪個配置文件
@ContextConfiguration("classpath:applicationContext.xml")
//指定多個配置文件時
@ContextConfiguration(locations = { "classpath*:/spring1.xml", "classpath*:/spring2.xml" })
public class Demo {
//將名為user的對象注入到u變量中
@Resource(name="user")
private User u;
@Test
public void fun1(){
System.out.println(u);
}
}