使用Spring可使用簡單的JavaBean實現之前EJB實現的功能, Spring是一個IOC和AOP容器框架java
public class HelloWorld {
private String name;
public void setName(String name) {
this.name = name;
}
public void hello() {
System.out.println("hello: " + name);
}
}
public class Main {
public static void main(String[] args) {
// 建立HelloWorld 的一個對象
HelloWorld helloWorld = new HelloWorld();
// 爲 name 屬性賦值
helloWorld.setName("kong");
// 調用hello 方法
helloWorld.hello();
}
}
複製代碼
一個簡單的helloWorld程序,其中第一步建立對象 和 第二步爲屬性賦值能夠交給Spring框架來完成spring
// 1. 建立Spring IOC 容器對象,容器對象會調用構造器並調用HelloWorld類中的setName方法
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. 從IOC容器中獲取Bean實例
HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
// 3. 調用 hello 方法
helloWorld.hello();
複製代碼
<bean id="helloWorld" class="com.atguigu.spring.beans.HelloWorld">
<property name="name" value="Spring"></property>
</bean>
複製代碼
IOC是翻轉資源獲取的方向, 傳統資源查找方式是組件向容器發起請求查找資源, 容器適時的返回資源, 應用了IOC以後,是容器主動將資源推送給它所管理的組件,組件要作的是選擇合適的方式來接收資源編程
DI: 組件以一些預先定義好的方式接受來自容器的資源注入設計模式
// 傳統方式
A a = getA();
B b = getB();
b.setA(a)
複製代碼
// 使用IOC實現
B b = getB();
複製代碼
##Spring配置Bean Spring屬性配置細節 如何配置Beanbash
配置方式: 基於XML文件的格式app
<bean id="helloWorld" class="com.atguigu.spring.beans.HelloWorld">
<property name="name" value="Spring"></property>
</bean>
class: 用於建立 bean的全類名,經過反射方式在IOC中建立bean, 要求bean中必需要有無參數的構造器
id: 用於獲取容器中的bean,id值惟一
複製代碼
Bean的配置方式: 經過全類名(反射)/經過工廠方法(靜態工廠方法 & 實例工廠方法)、FactoryBean框架
IOC容器BeanFactory & ApplicationContext概述ide
依賴注入的方式:ui
<constructor-arg>
元素裏聲明屬性,沒有name屬性index
type
來指定參數的位置和參數的類型以區分重載的構造器// 使用value屬性值類配置
<constructor-arg value="Audi" index="2"></constructor-arg>
// 使用value子節點來配置
<constructor-arg type="int">
<value>250</value>
</constructor-arg>
複製代碼
字面值: 能夠用字符串表示的值,能夠經過元素標籤或value屬性進行注入,基本數據類型及其封裝類、String等類型均可以採用字面值注入的方式this
使用property的ref屬性創建bean之間的引用關係
使用集合的基本標籤進行集合的配置,例如list
,array
,``
配置Properties屬性值
配置獨立的集合bean,以供多個bean進行引用,使用util
命名空間
<util:list id="cars">
<ref bean="car"/>
<ref bean="car2"/>
</util:list>
複製代碼
使用p
命名空間來爲bean的屬性賦值 <bean id="person" class="com.atguigu.spring.beans.Person" p:age="30" p:name="Queen" p:cars-ref='cars'></bean>
什麼是自動裝配: 在<bean>
的autowire屬性裏制定自動裝配的模式
在Person類當中定義了setter setter裏面有名字的信息,
自動裝配的缺點:
繼承關係: 配置上的繼承關係 bean配置的重用 使用<parent>
關鍵字
依賴關係: 某些bean要在前面建立 depends-on
關鍵字 好比要求在配置Person時,必需要有一個關聯的car! 換句話說person這個bean依賴於Car這個bean
使用scope
來設定做用域 默認狀況下是單例模式,相同類型的bean都是一樣的 prototype: 原型 容器初始化時不建立bean實例,而在每次請求時都建立一個新的Bean實例,並返回
好比須要用到系統部署的細節信息(好比文件路徑),這些信息須要和Spring文件分離
使用PropertyPlaceholderConfigurer的BeanFactory 後置處理器,該處理器容許用戶將Bean配置的部份內容外移動到屬性文件中,能夠在Bean配置文件中使用 ${var}
變量來從外部屬性文件中加載屬性,並使用這些屬性來替換變量
可使用SpEL語句進行擴展性的操做:
Spring容許在Bean聲明週期的特定點執行定製的任務 SpringIOC 容器對Bean的聲明週期進行管理的過程:
在Bean的聲明中設置init-method
和destroy-method
屬性,爲Bean指定 初始化和銷燬方法
在類裏面先將init方法(名字能夠自定義,保證對應就行)定義好,
<bean id="car" class="..." init-method="init" destroy-method="destroy">
複製代碼
ctx.close()
: 關閉IOC容器
建立Bean後置處理器 Bean後置處理器容許在調用初始化方法先後對Bean進行額外的處理
靜態工廠方法: 直接調用某一個類的靜態方法就能夠返回Bean的實例
class
: 指向靜態工廠方法的全類名factory-method
關鍵字: 指向靜態工廠方法的名字constructor-arg
: 若是工廠方法須要傳入參數,則使用constructor-arg來配置參數<bean id="car1" class="..." factory-method="getCar">
<constructor-arg value="audi"></constructor-arg>
</bean>
複製代碼
實例工廠方法:: 先要建立工廠自己,再經過調用工廠
factory-bean
: 指向實例工廠方法的beanfactory-method
關鍵字定義工廠bean的方法<bean id="carFactory" class="..."></bean>
<bean id="car2" factory-bean="" factory-method="..">
複製代碼
FactoryBean 是Spring提供的一個接口
class
: 指向FactoryBean的全雷鳴property
: 配置FactoryBean的屬性 實際返回的實例是FactoryBean的getObject() 返回的實例 便於有時候配置Bean的時候用到Spring當中的其它Bean在classpath中掃描組件
@Component
: 基本註解,標識一個Spring管理的組件@Respository
: 標識持久層組件@Service
: 標識服務層(業務層)@Controller
: 表現層組件 Spring默認命名策略: 使用非限定類名時,第一個字母小寫, 也能夠在註解中經過value屬性值標識組件的名稱須要在Spring配置文件中聲明<context:component-scan>
來限定掃描哪些包
指定一個須要掃描的基類包,Spring容器會掃描基類包以及其子包中的全部類,多個包能夠經過逗號分隔 context:exclude-filter
: 排除指定組件 context:include-filter
: 包含表達式組件
一個計算器接口,
須要完成兩個額外的需求, 生成日誌 + 進行驗證
日誌代碼差很少 核心代碼混亂,愈來愈多非業務需求,每一個方法在處理 還要兼顧其餘多個關注點
代碼分散: 只是爲了知足一個單一需求,不得不在多個模塊(方法)裏屢次重複相同的日誌代碼,若是日誌需求發生變化,必須修改全部模塊.
AOP方式解決
動態代理解決 代理設計模式: 使用一個代理將對象包裝起來,而後用該代理對象取代原始對象,任何對原始對象的調用都要經過代理
public class ArithmeticCalculatorLoggingProxy {
//要代理的對象
private ArithmeticCalculator target;
public ArithmeticCalculator getLoggingProxy() {
ArithmeticCalculator proxy = null;
// 代理對象由哪個類加載器負責加載
ClassLoader loader = target.getClass().getClassLoader();
// 代理對象的類型,即其中有哪些方法
Class[] interfaces = new Class[]{ArithmeticCalculator.class};
// 當調用代理對象其中的方法時,須要執行的代碼
InvocationHandler h = new InvocationHandler() {
/** * @param: proxy: 正在返回的代理對象,通常狀況下,invoke方法中不使用 * @param: method: 正在被調用的方法 * @args: 調用方法時,傳入的參數 */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke...");
return 0;
}
};
proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
return proxy;
}
}
複製代碼
動態是什麼意思?體如今哪裏?
橫切關注點方法 在應用AOP時,須要定義公共功能,但能夠明肯定義功能在哪裏,以何種方式應用,而且沒必要修改受影響的類.
AOP的好處:
計算器加減乘除的例子:
切面: 通知: 切面中的每個方法就是通知 鏈接點: 程序執行的某個特定位置 一個具體的存在 切點: 看不見 經過切點定位到特定鏈接點
在配置文件中加入AOP的命名空間 xmlns:aop="..."
基於註解的方式: 在配置文件中加入以下配置: 把橫切關注點的代碼抽象到切面的類中 切面首先是一個Java bean,須要加入@Component
註解 使用@Aspect
註解標註出切面,
@Before
: 方法執行前@After
: 方法執行後@AfterReturning
: 通知方法在目標方法返回後調用@AfterThrowing
: 通知方法在目標方法拋出異常後調用@Around
: 環繞execution() *
能夠表示任意修飾符及任意返回值
使用@Order
指定切面的優先級,值越小,優先級越高
從新用execution 那一坨東西 定義一個方法,用於聲明切入點表達式, 以後再用到該切點的地方就直接調用該方法便可聲明對應切點
@Pointcut("...")
public void declareJointPointExpression(){}
複製代碼
<aop:config>
<aop:aspect ref="audience">
<aop:before
pointcut="..." method="方法名"/>
<aop: after-returnning
pointcut="execution(...)"/>
</aop:aspect>
</aop:config>
複製代碼
必須爲不一樣的方法重寫相似的樣板代碼,存在大量的重複部分
public void purchase(String isbn, String username) {
Connection conn = null;
try {
conn = dataSource.getConnection();
conn.setAutoCommit(false);
...
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
if (conn != null) {
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
throw new RuntimeException(e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
複製代碼
編程式 聲明式
Spring
配置事務管理器 啓用事務註解 @Transactional