Spring (3)框架

Spring第三天筆記java

今日內容spring

  1. Spring的核心之一 -  AOP思想

(1) 代理模式- 動態代理express

① JDK的動態代理 (Java官方)編程

② CGLIB 第三方代理設計模式

(2) AOP思想在Spring中的具體體現(AOP底層使用的就是動態代理)數組

 

1. AOP概述

1.1. 什麼是AOP, 面向切面編程

AOPAspect Oriented Programming的縮寫, 意爲:面向切面編程, 經過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術. AOPOOP的延續, 是函數式編程的一種衍生範型. 利用AOP能夠對業務邏輯的各個部分進行隔離, 從而使得業務邏輯各部分之間的耦合度下降, 提升程序的可重用性, 同時提升了開發的效率. -解耦session

1.2. 傳統開發模型: 縱向的編程.

 

 

1.3. 面向切面編程: 縱橫配合的編程.

 

 

 

1.4. AOP的做用及優點

做用:app

在程序運行期間,不修改任何相關源碼對已有方法進行加強框架

優點:ide

減小重複代碼提升開發效率維護方便

1.5. AOP的實現方式

使用動態代理模式來實現

 

可能經過上面的介紹,咱們仍是沒有一個清晰的認識。不要緊,咱們看看下面的具體應用。

2. 案例中問題

經過下面的實現代碼,咱們能看出什麼問題嗎?

2.1. 模擬事務管理器

public class TransactionManagerHandler {

public void begin() {

System.out.println("開啓事務");

}

 

public void commit() {

System.out.println("提交事務");

}

 

public void rollback() {

System.out.println("回滾事務");

}

 

public void close() {

System.out.println("關閉session");

}

}

2.2. Service層代碼

public class UserServiceImpl implements UserService {

// 引入事務管理器

private TransactionManagerHandler txManager = new TransactionManagerHandler();

 

@Override

public void insert(String username) {

try {

txManager.begin();

System.out.println("調用dao層插入方法");

txManager.commit();

} catch (Exception e) {

txManager.rollback();

} finally {

txManager.close();

}

}

 

@Override

public void update(String username) {

try {

txManager.begin();

System.out.println("調用dao層修改方法");

txManager.commit();

} catch (Exception e) {

txManager.rollback();

} finally {

txManager.close();

}

}

}

 

2.3. 存在的問題

上面代碼的問題就是咱們的事務控制的代碼是重複性的。這還只是一個業務類,若是有多個業務了,每一個業務類中都會有這些重複性的代碼。是否是重複代碼太多了?

思考:咱們有什麼辦法解決這個問題嗎?

 

 

2.4. 解決上述問題的方案

  1. JDK的動態代理
  2. CGLIB代理
  3. SpringAOP技術(底層就是JDK動態代理和CGLIB代理技術)

 

3. 什麼是動態代理技術?

Java中的動態代理,就是使用者使用的不是真實的對象,而是使用的一個代理對象,而這個代理對象中包含的就是真實的對象,代理對象就是不改變原有對象的功能方法的基礎之上封裝新的功能

4. 使用JDK動態代理

JDK動態代理是Java官方的代理

 

使用JDK官方的Proxy類建立代理對象

  1. 須要經過Proxy建立代理對象
  2. 建立代理對象必需要一個代理處理類(實現了接口InvocationHandler的類)

 

4.1. DK動態代理API分析

1java.lang.reflect.Proxy :

Java 動態代理機制生成的全部動態代理類的父類,它提供了一組靜態方法來爲一組接口動態地生成代理類及其對象。

主要方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler hanlder)

方法職責:爲指定類加載器、一組接口及調用處理器生成動態代理類實例

參數:

   loader :類加載器

   interfaces :    模擬的接口

   hanlder :代理執行處理器

 

返回:動態生成的代理對象

2java.lang.reflect.InvocationHandler接口:

public Object invoke(Object proxy, Method method, Object[] args)

方法職責:負責集中處理動態代理類上的全部方法調用

參數:

    proxy :生成的代理對象

    method :當前調用的真實方法對象

args :當前調用方法的實參

 

返回: 真實方法的返回結果

------------------------------------------------------------------------------------

njdk動態代理操做步驟

① 實現InvocationHandler接口,建立本身加強代碼的處理器。

② 給Proxy類提供ClassLoader對象和代理接口類型數組,建立動態代理對象。

③ 在處理器中實現加強操做。

4.2. 案例代碼

在咱們的UserServiceImpl的實現類中,使用JDK的動態代理,進行方法的加強,加強事物的功能

JDK動態代理類

public class DynamicProxyHandler {

//被代理的對象

private Object target;

//事務管理器

private TransactionManagerHandler txManager;

/**

 * 返回一個代理對象,代理對象就作了方法的加強,(事物管理,日誌控制,權限管理等等)

 */

public <T> T getProxyObject(Class<T> clz) {

 

/*

 * JDK內置有一個代理類,專門負責建立動態代理對象的,類

 * Proxy 類 , Proxy爲被代理的對象建立代理對象

 *   理論上建立被代理對象,是須要被代理對象的類對應的字節碼的

 * Proxy 在JVM動態的建立被代理對象的字節碼,冬天的建立代理對象

 */

 

/*

 * loader: 類加載器,類加載器就是從當前classpath下面加載字節碼,在整個應用有且只有一個類加載器

 * 如何或者類加載器,

 * 方式一: 使用當前線程

 *      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

 *       方式二: 使用任何一個類的字節碼

 *      target.getClass().getClassLoader()

 * interfaces : 被代理對象的接口

 * h : 處理器: 真正作代碼加強的地方

 */

//代理對象

Object newProxyInstance = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {

/**

 * 代理內的加強方法,正常加強的地方

 * @param proxy 代理對象

 * @param method 被代理對象的方法

 * @param args 被代理對象方法的參數

 * @return  被代理對象執行的結果

 * @throws Throwable

 */

 

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

//執行被代理對象的方法

Object result = null;

try {

//方法以前執行操做

//開始事務

txManager.begin();

result = method.invoke(target, args);

//方法以後執行操做

//提交事物

txManager.commit();

} catch (Exception e) {

//回滾事物

txManager.rollback();

}finally {

txManager.close();

}

return result;

}

});

 

//返回代理對象

return (T) newProxyInstance;

}

 

public void setTarget(Object target) {

this.target = target;

}

 

public void setTxManager(TransactionManagerHandler txManager) {

this.txManager = txManager;

}

}

配置文件

<!-- 配置事物管理器 -->

    <bean id="txMananger" class="cn.zj.spring.TransactionManagerHandler"/>

    

    

    <!-- 配置動態代理類 -->

<bean id="dynamicProxy" class="cn.zj.spring.proxy.DynamicProxyHandler">

<!-- 注入事物管理器 -->

<property name="txManager" ref="txMananger"/>

 

<!-- 配置被代理對象 -->

<property name="target">

<bean class="cn.zj.spring.service.impl.UserServiceImpl"/>

</property>

</bean>    

測試代碼

@RunWith(SpringJUnit4ClassRunner.class) // 表示先啓動Spring容器,把junit運行在Spring容器中

@ContextConfiguration("classpath:applicationContext.xml") // 讀取Spring的配置文件

public class DynamicProxyTest {

// 自動注入 UserService

@Autowired

private DynamicProxyHandler proxy;

 

@Test

public void testInsert() throws Exception {

 

// 獲取代理類對象的中的獲取動態代理對象的方法

UserService proxyObject = proxy.getProxyObject(UserServiceImpl.class);

proxyObject.insert("張三");

}

@Test

public void testUpdate() throws Exception {

// 獲取代理類對象的中的獲取動態代理對象的方法

UserService proxyObject = proxy.getProxyObject(UserServiceImpl.class);

proxyObject.update("李四");

}

}

4.3. JDK動態代理的不足

1,JDK動態代理的對象必需要實現一個接口;

2,須要爲每一個對象建立代理對象;

3,動態代理的最小單位是類(全部類中的方法都會被處理),查詢方法不須要事務,可能不須要被代理

 

5. 使用CGLIB 第三方代理

CGLIB(Code Generation Library)是一個開源項目

CGLIBJDK動態代理同樣都是動態代理,可是CGLIB代理沒有接口能夠進行代理

 

Spring默認已經集成CGLIB代理,直接可使用便可,不用拷貝任何jar

 

5.1. 案例代碼

在咱們的UserServiceImpl的實現類中,使用CGLIB的動態代理,進行方法的加強,加強事物的功能

 

CGLIB代理類

public class CglibProxyHandler {

//被代理的對象

private Object target;

//事務管理器

private TransactionManagerHandler txManager;

/**

 * 返回一個代理對象,代理對象就作了方法的加強,(事物管理,日誌控制,權限管理等等)

 * @return

 */

public <T> T getProxyObject(Class<T> clz) {

 

//使用CGLIB代理,CGLIB代理 能夠沒有接口,直接使用類代理

 

//建立Enhancer CGLIB代理鍍錫

Enhancer enhancer = new Enhancer();

//設置類加載器

enhancer.setClassLoader(this.getClass().getClassLoader());

//設置被代理對象字節碼

enhancer.setSuperclass(target.getClass());

 

//代理的具體實現

enhancer.setCallback(new org.springframework.cglib.proxy.InvocationHandler() {

 

/**

 * 代理內的加強方法,正常加強的地方

 * @param proxy 代理對象

 * @param method 被代理對象的方法

 * @param args 被代理對象方法的參數

 * @return  被代理對象執行的結果

 * @throws Throwable

 */

 

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

//執行被代理對象的方法

Object result = null;

try {

//方法以前執行操做

//開始事務

txManager.begin();

result = method.invoke(target, args);

//方法以後執行操做

//提交事物

txManager.commit();

} catch (Exception e) {

//回滾事物

txManager.rollback();

}finally {

txManager.close();

}

return result;

}

});

 

 

 

//建立代理對象

Object proxy = enhancer.create();

 

//返回代理對象

return (T) proxy;

}

public void setTarget(Object target) {

this.target = target;

}

 

public void setTxManager(TransactionManagerHandler txManager) {

this.txManager = txManager;

}

}

配置文件

<!-- 配置事務管理器 -->

<bean id="txMananger" class="cn.zj.spring.TransactionManagerHandler"/>

 

<!-- 配置CGLIB代理類 -->

<bean id="dynamicProxy" class="cn.zj.spring.cglib.CglibProxyHandler">

<!-- 注入事務管理器 -->

<property name="txManager" ref="txMananger"/>

 

<!-- 配置被代理對象 -->

<property name="target">

<bean class="cn.zj.spring.service.impl.UserServiceImpl"/>

</property>

</bean>

測試代碼

@RunWith(SpringJUnit4ClassRunner.class) // 表示先啓動Spring容器,把junit運行在Spring容器中

@ContextConfiguration("classpath:applicationContext.xml") // 讀取Spring的配置文件

public class DynamicProxyTest {

// 自動注入 UserService

@Autowired

private DynamicProxyHandler proxy;

@Test

public void testInsert() throws Exception {

// 獲取代理類對象的中的獲取動態代理對象的方法

UserService proxyObject = proxy.getProxyObject(UserServiceImpl.class);

proxyObject.insert("張三");

}

@Test

public void testUpdate() throws Exception {

// 獲取代理類對象的中的獲取動態代理對象的方法

UserService proxyObject = proxy.getProxyObject(UserServiceImpl.class);

proxyObject.update("李四");

}

}

5.2. CGLIB代理總結

1,CGLIB能夠生成目標類的子類,並重寫父類非final修飾符的方法。

2,要求類不能是final的,要代理的方法要是非final、非static、非private的。

3,動態代理的最小單位是類(全部類中的方法都會被處理);

 

 

6. 代理小結

6.1. 解決代碼重複的方案

Spring中:

 

若目標對象實現了若干接口,Spring就會使用JDK動態代理。

若目標對象沒有實現任何接口,Spring就使用CGLIB庫生成目標對象的子類。

 

6.2. 直接使用代理的缺陷

  1. 若是直接使用代理解決代碼重複問題,咱們會發現,咱們每個類都要配置代理類,很是的麻煩

 

7. 動態代理模式的缺陷是什麼

動態代理模式的缺陷是:

  1. 必須須要實現類必需要有一個接口
  2. 沒法經過規則制定攔截的方法

 

如何解決這個問題:Spring提供了AOP的實現。

 

8. SpringAOP

Spring經過動態代理模式的實現後,咱們能夠定義AOP其實就是用於經過規則設置來攔截方法,加入能夠統一處理的代碼。

 

8.0.1. 關於代理的選擇

spring中,框架會根據目標類是否實現了接口來決定採用哪一種動態代理的方式。

8.0.2. AOP相關術語

Joinpoint(鏈接點):

所謂鏈接點是指那些被攔截到的點。在spring,這些點指的是方法,由於spring只支持方法類型的鏈接點。

  ---就是根據規則,能夠指定攔截的方法,咱們將每個被攔截的方法稱爲鏈接點。

 

Pointcut(切入點):

       --所謂的切入點,就是攔截方法設置的規則

所謂切入點是指咱們要對哪些Joinpoint進行攔截的定義。

 

Advice(通知/加強):

         --就是能夠設置在方法以前攔截或者方法執行以後攔截或者方法出異常後攔截,或者方法以前和以後都攔截。咱們將這些攔截場景稱爲通知

 

所謂通知是指攔截到Joinpoint以後所要作的事情就是通知。

通知的類型:前置通知,後置通知,異常通知,最終通知,環繞通知。

Aspect(切面):

          --所謂的切面就是咱們的攔截處理類

是切入點和通知的結合。

Weaving(織入):

-把切面加入到對象,並建立出代理對象的過程。(該過程由Spring來完成)

 

9. 基於XML配置AOP

經過XML的方式配置AOP

 

9.1. 搭建環境

9.1.1. 第一步:建立一個Java項目

需求:編寫一個切面類,在執行insert,update方法,分別在方法執行前、方法以後、異常出現後、分別方法執行先後調用編寫統一處理的代碼,

 

建立一個Java項目,加入Spring框架的基礎支持包

 

 

 

9.1.2. 第二步:編寫業務層類和接口

 

9.1.2.1. UserService 接口

package cn.zj.spring.service;

 

import cn.zj.spring.pojo.User;

 

public interface UserService {

void insert(User user);

void update(User user);

}

 

9.1.2.2. 業務層UserServiceImpl 實現類

package cn.zj.spring.service.impl;

 

import cn.zj.spring.pojo.User;

import cn.zj.spring.service.UserService;

 

public class UserServiceImpl implements UserService{

 

public void insert(User user) {

System.out.println("---調用DAO層保存方法---");

}

public void update(User user) {

System.out.println("---調用DAO層修改方法---");

}

}

 

 

9.1.3. 第三步:編寫Spring配置文件

引入aop的命名空間

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:p="http://www.springframework.org/schema/p"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop"

    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

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context.xsd

    http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop/spring-aop.xsd

    ">

    <!-- 配置UserService層 -->

<bean id="userService" class="cn.zj.spring.service.impl.UserServiceImpl"/>

</beans>

 

9.1.4. 第四步:編寫測試代碼

package cn.zj.spring.test;

 

import javax.annotation.Resource;

 

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

 

import cn.zj.spring.pojo.User;

import cn.zj.spring.service.impl.UserServiceImpl;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class UserServiceTest {

 

@Resource

private UserServiceImpl service;

 

@Test

public void testSave() {

User user = new User(null, "張三", "zhangsan@qq.com");

service.insert(user);

}

 

@Test

public void testUpdate() {

User user = new User(1, "李四", "lisi@qq.com");

service.update(user);

}

}

 

 

 

 

9.2. 配置AOP

9.2.1. 第一步:加入AOP的支持包

AOP 思想必須使用AspectJ語法,而AOP思想不是Spring框架設計出來的,而是叫一個AOP聯盟組織提出這種思想,因此開發者須要導入 AOP聯盟提供的 aspectjweaver.jaraspectweaver織入包)

 

 

 

 

9.2.2. 第二步:編寫一個切面類

package cn.zj.spring;

 

import java.util.Arrays;

 

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

 

public class TransactionManagerHandler {

 

/**

 * 環繞加強的方法

 *

 * @param pjp ProceedingJoinPoint 鏈接點 ProceedingJoinPoint 鏈接點

 *

 */

public void allInOne(ProceedingJoinPoint pjp) {

try {

begin(pjp);

// 執行方法

pjp.proceed(); //此方法在環繞方法中能夠調用正在的業務方法

 

System.out.println("提交事務");

 

} catch (Throwable e) {

System.out.println("回滾事務 :" + e.getMessage());

} finally {

System.out.println("關閉session");

}

}

 

// JoinPoint : 鏈接點, 獲取被代理對象的相關信息

public void begin(JoinPoint jp) {

// 獲取被代理對象的類型

Class<?> clz = jp.getTarget().getClass();

System.out.println(clz);

// 獲取被代理對象執行方法對應的參數

Object[] args = jp.getArgs();

System.out.println(Arrays.toString(args));

System.out.println("開啓事務");

}

 

public void begin() {

System.out.println("開啓事務");

}

 

public void commit() {

System.out.println("提交事務");

}

 

/*

 * public void rollback() { System.out.println("回滾事務"); }

 */

 

public void rollback(Throwable e) {

 

System.out.println("回滾事務 : " + e.getMessage());

}

 

public void close() {

System.out.println("關閉session");

}

}

 

9.2.3. 第三步:配置AOP配置

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:p="http://www.springframework.org/schema/p"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop"

    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

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context.xsd

    http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop/spring-aop.xsd

    ">

   

    <!-- 配置UserService層 -->

<bean id="userService" class="cn.zj.spring.service.impl.UserServiceImpl"/>

 

 

 <!-- 配置事物管理器  -->

    <bean id="txMananger" class="cn.zj.spring.TransactionManagerHandler"/>

    

<!-- AOP 相關配置: W (where)W(when)W(what) 原則   -->

 

<!-- 配置切入點: where -->

<aop:config>

<!-- 作什麼(what:加強的功能) -->

<aop:aspect ref="txMananger">

<!-- 切入點(Pointcut):在哪些類,哪些方法上切入(where); -->

<aop:pointcut expression="execution( * cn.zj.spring.service..*.*(..))" id="pt"/>

 

<!-- 加強(Advice):早期翻譯爲通知,在方法執行的什麼時機(when:方法前/方法後/方法先後)

前置加強 : method : 須要加強的方法  -->

<aop:before method="begin" pointcut-ref="pt"/>

 

 

<aop:after-returning method="commit" pointcut-ref="pt"/><!-- 後置加強 -->

 

<!-- 異常加強 : 拋出的異是常異常頂級類Throwable

throwing : 是異常增城方法,參數的名稱: 必須和參數一致 -->

<aop:after-throwing  throwing="e"  method="rollback" pointcut-ref="pt"/><!-- 異常加強 -->

 

<aop:after method="close"  pointcut-ref="pt"/><!-- 最終加強 -->

 

<!-- 環繞加強: 將多個增長集中到一塊兒了  -->

<!-- <aop:around method="allInOne" pointcut-ref="pt"/> -->

 

</aop:aspect>

<!-- 織入(Weaving):把切面加入到對象,並建立出代理對象的過程。(該過程由Spring來完成)。  -->

</aop:config> 

</beans>

9.3. 切入點表達式說明

execution:

匹配方法的執行(經常使用)

execution(表達式)

表達式語法:execution([修飾符] 返回值類型 包名.類名.方法名(參數))

寫法說明:

全匹配方式:

public void cn.zj.service.impl.CustomerServiceImpl.saveCustomer()

訪問修飾符能夠省略

void com.zj.service.impl.CustomerServiceImpl.saveCustomer()

返回值可使用*號,表示任意返回值

* com.zj.service.impl.CustomerServiceImpl.saveCustomer()

包名可使用*號,表示任意包,可是有幾級包,須要寫幾個*

* *.*.*.*.CustomerServiceImpl.saveCustomer()

使用..來表示當前包,及其子包

* com..CustomerServiceImpl.saveCustomer()

類名可使用*號,表示任意類

* com..*.saveCustomer()

方法名可使用*號,表示任意方法

* com..*.*()

參數列表可使用*,表示參數能夠是任意數據類型,可是必須有參數

* com..*.*(*)

參數列表可使用..表示有無參數都可,有參數能夠是任意類型

* com..*.*(..)

全通配方式:

* *..*.*(..)

9.4. 經常使用標籤

9.4.1. <aop:config>

做用:

用於聲明開始aop的配置

9.4.2. <aop:aspect>

做用:

用於配置切面。

屬性:

id:給切面提供一個惟一標識。

ref:引用配置好的通知類beanid

9.4.3. <aop:pointcut>

做用:

用於配置切入點表達式

屬性:

expression:用於定義切入點表達式。

id:用於給切入點表達式提供一個惟一標識。

9.4.4. <aop:before>

做用:

用於配置前置通知

屬性:

method:指定通知中方法的名稱。

pointct:定義切入點表達式

pointcut-ref:指定切入點表達式的引用

9.4.5. <aop:after-returning>

做用:

用於配置後置通知若是出了異常就必定不會調用切面的方法

屬性:

method:指定通知中方法的名稱。

pointct:定義切入點表達式

pointcut-ref:指定切入點表達式的引用

9.4.6. <aop:after-throwing>

做用:

用於配置異常通知只有出了異常纔會調用切面對應的方法

屬性:

method:指定通知中方法的名稱。

pointct:定義切入點表達式

pointcut-ref:指定切入點表達式的引用

9.4.7. <aop:after>

做用:

用於配置最終通知無論出不出異常,調用的切面的方法

屬性:

method:指定通知中方法的名稱。

pointct:定義切入點表達式

pointcut-ref:指定切入點表達式的引用

9.4.8. <aop:around>

做用:

用於配置環繞通知

屬性:

method:指定通知中方法的名稱。

pointct:定義切入點表達式

pointcut-ref:指定切入點表達式的引用

10. 基於註解配置AOP

10.1. 搭建環境

10.1.1. 第一步:建立一個Java項目

建立一個Java項目,加入Spring框架的基礎支持包

 

 

 

10.1.2. 第二步:編寫業務層類和接口

 

10.1.2.1. UserService 接口

package cn.zj.spring.service;

 

import cn.zj.spring.pojo.User;

 

public interface UserService {

void insert(User user);

void update(User user);

}

 

10.1.2.2. 業務層UserServiceImpl 實現類

package cn.zj.spring.service.impl;

 

import cn.zj.spring.pojo.User;

import cn.zj.spring.service.UserService;

 

public class UserServiceImpl implements UserService{

 

public void insert(User user) {

System.out.println("---調用DAO層保存方法---");

}

public void update(User user) {

System.out.println("---調用DAO層修改方法---");

}

}

 

 

10.1.3. 第三步:編寫Spring配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:p="http://www.springframework.org/schema/p"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop"

    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

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context.xsd

    http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop/spring-aop.xsd

    ">

    <!-- 配置UserService層 -->

<bean id="userService" class="cn.zj.spring.service.impl.UserServiceImpl"/>

</beans>

 

10.1.4. 第四步:編寫測試代碼

package cn.zj.spring.test;

 

import javax.annotation.Resource;

 

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

 

import cn.zj.spring.pojo.User;

import cn.zj.spring.service.impl.UserServiceImpl;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class UserServiceTest {

 

@Resource

private UserServiceImpl service;

 

@Test

public void testSave() {

User user = new User(null, "張三", "zhangsan@qq.com");

service.insert(user);

}

 

@Test

public void testUpdate() {

User user = new User(1, "李四", "lisi@qq.com");

service.update(user);

}

}

 

 

10.2. 配置AOP

10.2.1. 第一步:加入AOP的支持包

--注意:必需要導入加入支持AOP的包。

SpringAOP包基於AspectJ框架,因此必須加入AspectJ-->aspectjweaver.jar

 

 

 

10.2.2. 第二步:編寫一個切面類

package cn.zj.spring;

 

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.springframework.stereotype.Component;

 

@Component

@Aspect //在此類中可使用註解進行aop的相關配置 <aop:aspect>

public class TransactionManagerHandler {

 

//<aop:pointcut expression="execution( * cn.zj.spring.service..*.*(..))" id="當前方法名就是id"/>

@Pointcut("execution( * cn.zj.spring.service..*.*(..))")

public void pointcut() {}

 

@Before("pointcut()") //<aop:before method="begin" pointcut-ref="pt"/>

public void begin() {

System.out.println("開啓事務");

}

 

@AfterReturning("pointcut()")//<aop:after-returning method="commit" pointcut-ref="pt"/>

public void commit() {

System.out.println("提交事務");

}

 

//<aop:after-throwing  throwing="e"  method="rollback" pointcut-ref="pt"/>

@AfterThrowing(pointcut="pointcut()",throwing="ex")

public void rollback(Throwable ex) {

System.out.println("註解的回滾事務 : " + ex.getMessage());

}

 

@After("pointcut()")//<aop:after method="close"  pointcut-ref="pt"/>

public void close() {

System.out.println("關閉session");

}

 

//環繞加強

@Around("pointcut()") //<aop:around method="allInOne" pointcut-ref="pt"/>

public Object allInOne(ProceedingJoinPoint pjp) {

Object result = null;

try {

System.out.println("開啓事務------");

//執行被代理對象當前須要執行業務方法

result = pjp.proceed();

System.out.println("提交事務------");

} catch (Throwable ex) {

System.out.println("------回滾事務 : " + ex.getMessage());

}finally {

System.out.println("關閉session------");

}

return result;

}

}

 

 

10.2.3. 第三步:配置AOP配置

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:p="http://www.springframework.org/schema/p"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop"

    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

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context.xsd

    http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop/spring-aop.xsd

    ">

   <!-- 配置spring的包掃描 -->

   <context:component-scan base-package="cn.zj.spring"/>

   <!-- 使用註解配置AOP配置配置自動注入AOP -->

   <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

 

</beans>

 

10.3. 經常使用註解

10.3.1. @Aspect

做用:

把當前類聲明爲切面類。

10.3.2. @Before

做用:

把當前方法當作是前置通知。

屬性:

value:用於指定切入點表達式,還能夠指定切入點表達式的引用。

10.3.3. @AfterReturning

做用:

把當前方法當作是後置通知。報異常,就不執行

屬性:

value:用於指定切入點表達式,還能夠指定切入點表達式的引用。

10.3.4. @AfterThrowing

做用:

把當前方法當作是異常通知。只有報異常才執行

 

屬性:

value:用於指定切入點表達式,還能夠指定切入點表達式的引用。

10.3.5. @After

做用:

把當前方法當作是最終通知。無論報不報異常都執行

屬性:

value:用於指定切入點表達式,還能夠指定切入點表達式的引用。

10.3.6. @Around

做用:

把當前方法當作是環繞通知。

屬性:

value:用於指定切入點表達式,還能夠指定切入點表達式的引用。

10.3.7. @Pointcut

做用:

指定切入點表達式

屬性:

value:指定表達式的內容

 

 

 

 

 

11. 小結

今日內容

 

AOP 思想

  1. AOP 面向切面編程

(1) 目的: 減小重複代碼

  1. AOP的底層原理(使用Java動態代理技術-動態代理技術就是java設計模式代理模式的一種具體體現)
  2. 什麼動態代理?

(1) Java動態代理,不直接編寫類的代理類,在程序的運行過程當中,在JVM中動態的爲被代理的類建立一份新的字節碼,並使用這份新的字節碼建立對應的代理對象。

(2) JDK 動態代理

① 缺點:必須有接口代理,沒有接口不能代理

② 使用的 java.lang.reflect.Proxy 代理的靜態方法

1) Object obj  = Proxy.newProxyInstance(類加載器,被代理數據類型的接口字節碼,處理器)

(3) CGLIB代理

① 便可有接口的類,又能夠沒有接口的類

1) 使用Enhancer 類建立代理對象

  1. AOP 的專業名詞(術語)

(1) Joinpoint 鏈接點(具體的方法)

(2) Pointcut 切入點 具體的某一類方法

(3) Advice 通知/加強 (具體要作的事情,如:事務處理)

(4) Aspect :切面 = 切入點(pointcut+通知(advice

(5) Weaving  織入,將整個AOP的配置在運行階段組織在一塊兒,由Spring框架完成

  1. AOPxml配置

(1) 引入相關的依賴包

(2) 引入命名空間(通俗講:xml約束配置)

(3) AOPxml標籤具體配置

  1. AOP註解配置
相關文章
相關標籤/搜索