Spring中的AOP(8)
AOP:不是由Spring定義.AOP聯盟的組織定義.
Spring中的通知:(增強代碼)
-
前置通知 org.springframework.aop.MethodBeforeAdvice
* 在目標方法執行前實施增強 - 後置通知 org.springframework.aop.AfterReturningAdvice
* 在目標方法執行後實施增強 - 環繞通知 org.aopalliance.intercept.MethodInterceptor
* 在目標方法執行前後實施增強 - 異常拋出通知 org.springframework.aop.ThrowsAdvice
* 在方法拋出異常後實施增強 - 引介通知 org.springframework.aop.IntroductionInterceptor(課程不講.)
* 在目標類中添加一些新的方法和屬性
Spring中的切面類型
-
Advisor : Spring中傳統切面.
* Advisor:都是有一個切點和一個通知組合.
* Aspect:多個切點和多個通知組合. - Advisor : 代表一般切面,Advice本身就是一個切面,對目標類所有方法進行攔截(* 不帶有切點的切面.針對所有方法進行攔截)
- PointcutAdvisor : 代表具有切點的切面,可以指定攔截目標類哪些方法(帶有切點的切面,針對某個方法進行攔截)
- IntroductionAdvisor : 代表引介切面,針對引介通知而使用切面(不要求掌握)
Spring的AOP的開發
針對所有方法的增強:(不帶有切點的切面)
- 第一步:導入相應jar包.
* spring-aop-3.2.0.RELEASE.jar
* com.springsource.org.aopalliance-1.0.0.jar - 第二步:編寫被代理對象:
* CustomerDao接口
package cn.spring3.demo3; /*接口類 */ public interface CustomerDao { public void add(); public void update(); public void delete(); public void find(); }
* CustoemrDaoImpl實現類
package cn.spring3.demo3;
/**
* @author NOP
* 針對所有方法的增強
*/
public class CustomerDaoImpl implements CustomerDao {
public void add() {
System.out.println("添加客戶");
}
public void delete() {
System.out.println("刪除客戶");
}
public void find() {
System.out.println("查詢客戶");
}
public void update() {
System.out.println("修改客戶");
}
}
- 第三步:編寫增強的代碼:
package cn.spring3.demo3;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
/**
* @author NOP
* 前置增強
*/
public class MyBeforeAdvice implements MethodBeforeAdvice{
/**
* method:執行的方法
* args:參數
* target:目標對象
*/
public void before(Method method, Object[] args, Object target)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("前置增強...");
}
}
- 第四步:生成代理:(配置生成代理:)
* 生成代理Spring基於ProxyFactoryBean類.底層自動選擇使用JDK的動態代理還是CGLIB的代理.
* 屬性:
target : 代理的目標對象
proxyInterfaces : 代理要實現的接口
如果多個接口可以使用以下格式賦值
<list>
<value></value>
....
</list>
proxyTargetClass : 是否對類代理而不是接口,設置為true時,使用CGLib代理
interceptorNames : 需要織入目標的Advice
singleton : 返回代理是否為單實例,默認為單例
optimize : 當設置為true時,強制使用CGLib
<!-- 傳統方式代理 -->
<!-- 不帶有切點的切面 -->
<!-- 目標對象 -->
<bean id="customerDao" class="cn.spring3.demo3.CustomerDaoImpl"></bean>
<!-- 定義增強 -->
<bean id="beforeAdvice" class="cn.spring3.demo3.MyBeforeAdvice"></bean>
<!-- Srping配置增強代理 -->
<bean id="customerDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 設置目標對象 -->
<property name="target" ref="customerDao"></property>
<!-- 設置實現的接口 ,value中寫接口的全路徑-->
<property name="proxyInterfaces" value="cn.spring3.demo3.CustomerDao"></property>
<!-- 需要使用的value:要的名稱 -->
<property name="interceptorNames" value="beforeAdvice"></property>
<!-- 強制使用CGLib代理
<property name="optimize" value="true"/>
-->
</bean>
<!-- 不帶有切點的切面 -->
第五步:編寫測試類
package cn.spring3.demo3;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest3 {
@Autowired
//@Qualifier("customerDao")//註入的真實的對象,必須註入代理對象
@Qualifier("customerDaoProxy")
private CustomerDao customerDao;
/*
* 不帶有切點的切面
*/
@Test
public void demo1(){
customerDao.add();
customerDao.delete();
customerDao.find();
customerDao.update();
}
}
測試結果:
前置增強...
添加客戶
前置增強...
刪除客戶
前置增強...
查詢客戶
前置增強...
修改客戶
帶有切點的切面:(針對目標對象的某些方法進行增強)
- PointcutAdvisor 接口:
- DefaultPointcutAdvisor 最常用的切面類型,它可以通過任意Pointcut和Advice 組合定義切面
- RegexpMethodPointcutAdvisor 構造正則表達式切點切面
第一步:創建被代理對象.
* OrderDao
package cn.spring3.demo4;
/**
* @author NOP
* 目標對象
*/
public class OrderDao {
public void add() {
// TODO Auto-generated method stub
System.out.println("添加訂單");
}
public void delete() {
// TODO Auto-generated method stub
System.out.println("刪除訂單");
}
public void find() {
// TODO Auto-generated method stub
System.out.println("查詢訂單");
}
public void update() {
// TODO Auto-generated method stub
System.out.println("修改訂單");
}
}
第二步:編寫增強的類:
package cn.spring3.demo4;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* @author NOP 增強的類 使用的是環繞
*/
public class MyAroundAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
// TODO Auto-generated method stub
System.out.println("環繞前增強。。。");
Object result = methodInvocation.proceed();// 執行目標對象的方法
System.out.println("環繞後增強。。。");
return result;
}
}
第三步:生成代理:
<!-- 帶有切點的切面 -->
<!-- 目標對象 -->
<bean id="orderDao" class="cn.spring3.demo4.OrderDao"></bean>
<!-- 定義增強 -->
<bean id="aroundAdvice" class="cn.spring3.demo4.MyAroundAdvice"></bean>
<!-- ********************************定義切點*************** -->
<bean id="mypointcutAdviesor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!--定義正則表達式,規定哪些方法執行攔截 pattern是一個方法patterns是多個方法-->
<!-- <property name="pattern" value=".*"/> 這個正則是所有-->
<!--<property name="pattern" value="cn\.spring3\.demo4\.OrderDao\.delete.*"/>-->
<!--<property name="pattern" value=".*add.*"/>-->
<property name="patterns" value=".*add.*,.*update.*"/>
<!-- 應用增強 -->
<property name="advice" ref="aroundAdvice"/>
</bean>
<!-- ********************************定義切點*************** -->
<!-- 定義生成代理對象 -->
<bean id="orderDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 設置目標對象 -->
<property name="target" ref="orderDao"></property>
<!-- 針對類的代理-->
<property name="proxyTargetClass" value="true"></property>
<!-- 在目標上應用增強 -->
<property name="interceptorNames" value="mypointcutAdviesor"></property>
</bean>
<!-- 帶有切點的切面 -->
第四步:編寫測試類
package cn.spring3.demo4;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest1 {
@Autowired
//@Qualifier("orderDao")//註入的真實的對象,必須註入代理對象
@Qualifier("orderDaoProxy")
private OrderDao orderDao;
/*
* 帶有切點的切面
*/
@Test
public void demo1(){
orderDao.add();
orderDao.delete();
orderDao.find();
orderDao.update();
}
}
測試結果:
環繞前增強。。。
添加訂單
環繞後增強。。。
刪除訂單
查詢訂單
環繞前增強。。。
修改訂單
環繞後增強。。。
自動代理
-
前面的案例中,每個代理都是通過ProxyFactoryBean織入切面代理,在實際開發中,非常多的Bean每個都配置ProxyFactoryBean開發維護量巨大
- 自動創建代理(*****基於後處理Bean.在Bean創建的過程中完成的增強.生成Bean就是代理.)
- BeanNameAutoProxyCreator 根據Bean名稱創建代理
- DefaultAdvisorAutoProxyCreator 根據Advisor本身包含信息創建代理
- * AnnotationAwareAspectJAutoProxyCreator 基於Bean中的AspectJ 註解進行自動代理
自動方式代理沒有切點切面的增強
<!-- 自動方式代理沒有切點切面的增強 -->
<!-- 目標對象 -->
<bean id="customerDao" class="cn.spring3.demo3.CustomerDaoImpl"></bean>
<bean id="orderDao" class="cn.spring3.demo4.OrderDao"></bean>
<!-- 定義增強 -->
<bean id="beforeAdvice" class="cn.spring3.demo3.MyBeforeAdvice"></bean>
<bean id="aroundAdvice" class="cn.spring3.demo4.MyAroundAdvice"></bean>
<!-- 自動代理:按名稱的代理 基於後處理Bean,後處理Bean不需要配置ID -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="*Dao"/>
<property name="interceptorNames" value="beforeAdvice"/>
</bean>
編寫測試類:
package cn.spring3.demo5;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import cn.spring3.demo3.CustomerDao;
import cn.spring3.demo4.OrderDao;
/**
* @author NOP
* 自動方式代理沒有切點切面的增強
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class SpringTest {
@Autowired
@Qualifier("orderDao")//不用註入代理,因為類已經是代理了
private OrderDao orderDao;
@Autowired
@Qualifier("customerDao")
private CustomerDao customerDao;
@Test
public void demo1(){
orderDao.add();
orderDao.delete();
customerDao.find();
customerDao.update();
}
}
測試結果:
前置增強...
添加訂單
前置增強...
刪除訂單
前置增強...
查詢客戶
前置增強...
修改客戶
自動方式代理 有切點切面的增強
<!-- 自動方式代理 有切點切面的增強 -->
<!-- 目標對象 -->
<bean id="customerDao" class="cn.spring3.demo3.CustomerDaoImpl"></bean>
<bean id="orderDao" class="cn.spring3.demo4.OrderDao"></bean>
<!-- 定義增強 -->
<bean id="beforeAdvice" class="cn.spring3.demo3.MyBeforeAdvice"></bean>
<bean id="aroundAdvice" class="cn.spring3.demo4.MyAroundAdvice"></bean>
<!-- 定義切點 -->
<bean id="mypointcutAdviesor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!--定義正則表達式,規定哪些方法執行攔截 -->
<property name="patterns" value=".*add.*,.*update.*"/>
<!-- 應用增強 -->
<property name="advice" ref="beforeAdvice"/>
</bean>
<!-- 自動代理:按名稱的代理 基於後處理Bean,後處理Bean不需要配置ID -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="*Dao"/>
<property name="interceptorNames" value="mypointcutAdviesor"/>
</bean>
編寫測試類:
package cn.spring3.demo5;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import cn.spring3.demo3.CustomerDao;
import cn.spring3.demo4.OrderDao;
/**
* @author NOP
* 自動方式代理 有切點切面的增強
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class SpringTest_1 {
@Autowired
@Qualifier("orderDao")
private OrderDao orderDao;
@Autowired
@Qualifier("customerDao")
private CustomerDao customerDao;
@Test
public void demo1(){
orderDao.add();
orderDao.delete();
orderDao.update();
orderDao.find();
customerDao.add();
customerDao.delete();
customerDao.update();
customerDao.find();
}
}
測試結果:
前置增強...
添加訂單
刪除訂單
前置增強...
修改訂單
查詢訂單
前置增強...
添加客戶
刪除客戶
前置增強...
修改客戶
查詢客戶
區分基於ProxyFactoryBean的代理與自動代理區別?
***** ProxyFactoryBean:先有被代理對象,將被代理對象傳入到代理類中生成代理.
自動代理基於後處理Bean.在Bean的生成過程中,就產生了代理對象,把代理對象返回.生成Bean已經是代理對象.
Spring中的AOP(8)