Spring的AOP配置
Spring的AOP配置
1.先寫一個普通類:
package com.spring.aop;
public class Common {
public void execute(String username,String password){
System.out.println("------------------普通類----------------");
}
}
2.寫一個切面類,用於合法性校驗和日誌新增:
package com.spring.aop;
public class Check {
public void checkValidity(){
System.out.println("------------------
}
public void addLog(JoinPoint j){
System.out.println("------------------新增日誌----------------");
Object obj[] = j.getArgs();
for(Object o :obj){
System.out.println(o);
}
System.out.println("========checkSecurity=="+j.getSignature().getName());//這個是獲得方法名
}
}
3.
<bean id="common" class="com.spring.aop.Common"/>
<bean id="check" class="com.spring.aop.Check"/>
<aop:config>
<aop:aspect id="myAop" ref="check">
<aop:pointcut id="target" expression="execution(* com.spring.aop.Common.execute(..))"/>
<aop:after method="addLog" pointcut-ref="target"/>
</aop:aspect>
</aop:config>
</beans>
注意:
execution(* com.spring.aop.*.*(..))"/
這樣寫應該就可以了
這是com.aptech.jb.epet.dao.hibimpl 包下所有的類的所有方法。。
第一個*代表所有的返回值型別
第二個*代表所有的類
第三個*代表類所有方法
最後一個..代表所有的引數。
4.最後寫一個測試:
package com.spring.aop;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Client {
public static void main(String[] args) {
BeanFactory factory=new ClassPathXmlApplicationContext("applicationContext-aop.xml");
Common c=(Common) factory.getBean("common");
c.execute("zhengjunhua","zhengjunhua");
}
}
注意:
需要新增三個包:spring-aop.jar , aspectjrt.jar ,aspectjweaver.jar,否則會報錯。
輸出結果:
------------------驗證合法性----------------
------------------普通類----------------
------------------新增日誌----------------
zhengjunhua
zhengjunhua
========checkSecurity==execute
Spring實現動態代理配置是有兩種配置檔案:
1、xml檔案方式;
2、annotation方式(使用AspectJ類庫實現的。)
一、AOP配置annotation方式(一)搭建annotation開發環境首先:需要在配置檔案中加入@AspectJ標籤
<aop:aspectj-autoproxy/>
自動幫我產生代理
注意:Spring預設並沒有加入aop的xsd檔案,因為我們需要手動加入(紅色部分)
<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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop
<context:annotation-config/>
<context:component-scanbase-package="com.wjt276"/>
<aop:aspectj-autoproxy/>
</beans>
另外需要引用aspectJ的jar包:
aspectjweaver.jar
aspectjrt.jar
(二)aspectJ類庫AspectJ是一個專門用來實現動態代理(AOP程式設計)的類庫
AspectJ是面向切面程式設計的框架
Spring使用就是這個類庫實現動態代理的
(三)AOP的annotation例項要求:在執行save()方法之前加入日誌邏輯
1、spring的配置檔案同上面的
2、model類、dao層類、service層類都與上面天下一致
3、切面類(LogInterceptor)
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
publicclass LogInterceptor {
@Before("execution(public void com.wjt276.dao.impl.UserDaoImpl.save(com.wjt276.model.User))")
publicvoid before(){
System.out.println("method start...");
}
}
結果:這樣在執行public void com.wjt276.dao.impl.UserDaoImpl.save(com.wjt276.model.User)方法之前就會先執行這個邏輯了。
注意:
1、@Aspect:意思是這個類為切面類
2、@Componet:因為作為切面類需要Spring管理起來,所以在初始化時就需要將這個類初始化加入Spring的管理;
3、@Befoe:切入點的邏輯(Advice)
4、execution…:切入點語法
(四)
三個連線點(切入點) |
1、JoinPoint
切入面 |
連線點(切入點)
程式執行過程 |
2、PointCut
切入點人集合
當需要定義一個切入點時,則需要使用這個
@Pointcut("execution(* com.xyz.someapp.service.*.*(..))")
public void businessService() {}
3、Aspect
切面
4、Advice
切入點的邏輯
例如上例中的@Before
5、Target
被代理物件
6、Weave
織入
(五)織入點語法1、無返回值、com.wjt276.dao.impl.UserDaoImpl.save方法引數為User
execution(public void com.wjt276.dao.impl.UserDaoImpl.save(com.wjt276.model.User))
2、任何包、任何類、任何返回值、任何方法的任何引數
execution(public * *(..))
3、任何包、任何類、任何返回值、任何set開頭方法的任何引數
execution(* set*(..))
4、任何返回值、com.xyz.service.AccountService類中的任何方法、任何引數
execution(* com.xyz.service.AccountService.*(..))
5、任何返回值、com.xyz.service包中任何類中的任何方法、任何引數
execution(* com.xyz.service.*.*(..))
6、任何返回值、com.xyz.service包中任何層次子包(..)、任何類、任何方法、任何引數
execution(* com.xyz.service..*.*(..))
7、void 和 !void(非void)
execution(public void com.xyz.service..*.*(..))
execution(public !void com.xyz.service..*.*(..))
注意:上以是AspectJ的織入點語法,Spring AOP也實現了自己的織入點語法,同樣可以使用
within(com.xyz.service.*)
within(com.xyz.service..*)
this(com.xyz.service.AccountService)
target(com.xyz.service.AccountService)
args(java.io.Serializable)
@target(org.springframework.transaction.annotation.Transactional)
@within(org.springframework.transaction.annotation.Transactional)
@annotation(org.springframework.transaction.annotation.Transactional)
@args(com.xyz.security.Classified)
bean(tradeService)
bean(*Service)
(六)Advice1、@Before執行方法之前
@Aspect
public class BeforeExample {
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() { // ... }}
@Aspect
public class BeforeExample {
@Before("execution(* com.xyz.myapp.dao.*.*(..))")
public void doAccessCheck() { // ... }}
2、@ AfterReturning方法正常執行完之後
@Aspect
public class AfterReturningExample {
@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() { // ... }}
@Aspect
public class AfterReturningExample {
@AfterReturning(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
returning="retVal")
public void doAccessCheck(Object retVal) { // ... }}
3、@ AfterThrowing方法丟擲異常之後
@Aspect
public class AfterThrowingExample {
@AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doRecoveryActions() { // ... }}
@Aspect
public class AfterThrowingExample {
@AfterThrowing(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) { // ... }}
4、 @After (finally)方法丟擲異常被catch之後,需要進行的部分(相當於finally功能)
@Aspect
public class AfterFinallyExample {
@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doReleaseLock() { // ... }}
5、@ Around在方法之前和之後都要加上
但是需要一個引數ProceedingJoinPoint,並者需要Object retVal = pjp.proceed();
和返回return retVal;
@Aspect
public class AroundExample {
@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal; }}
(七)Pointcut當多個Advice個有相同的織入點。那麼我們可以定義一個織入點集合,在需要使用的地方,呼叫就可以了。
例如:
@Aspect
@Component
publicclass LogInterceptor {
@Pointcut("execution(public * com.wjt276.dao..*.*(..))")
publicvoid myMethod(){};
@Before(value="myMethod()")
publicvoid before(){
System.out.println("method start...");
}
@AfterReturning("myMethod()")
publicvoid afterReturning(){
System.out.println("method after returning...");
}}
注意:那個空方法,只是為了給Pointcut起個名字,以方便別處使用
(八)annotatin方式的AOP例項import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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;
@Aspect
@Component
publicclass LogInterceptor {
@Pointcut("execution(public * com.wjt276.dao..*.*(..))")
publicvoid myMethod(){};
@Before(value="myMethod()")
publicvoid before(){
System.out.println("method start...");
}
@AfterReturning("myMethod()")
publicvoid afterReturning(){
System.out.println("method after returning...");
}
@Around(value="myMethod()")
publicvoid around(ProceedingJoinPoint pjp) throws Throwable{
//因為@around需要傳入一個引數ProceedingJoinPoint進行前後加邏輯
System.out.println("method around start...");
//在需要前後邏輯的中間加入下列語句。表示前後邏輯,可能會丟擲異常Throwable。
pjp.proceed();
System.out.println("method around end...");
}
}
二、AOP配置xml方式xml方式是我們以後使用的比較多的,因為當切面類我們沒有原始碼時、當我們使用第三方的切面類時,我就不能使用annotation的方式,而且如果使用annotation方式一但程式編譯後就不可以修改了。如果使用xml方式就不一樣了,我們只需要修改xml檔案就可以了。
xml方式與annotation的作用是一樣。現在就是例項:
<?xml version="1.0"encoding="UTF-8"?>
<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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<context:annotation-config/>
<context:component-scanbase-package="com.wjt276"/>
<beanid="logInterceptor"class="com.wjt276.aop.LogInterceptor"></bean>
<aop:config>
<!-- <aop:pointcut >在此處定義的pointcut是全域性的pointcut可以供所有的aspect使用
id:表示這個pointcut的名稱,以方便使用-->
<aop:pointcutid="myMethod"
expression="execution(public * com.wjt276.service..*.*(..))"/>
<!-- <aop:aspect>表示定義一個切面類(這需要Spring初始化加入其管理)
id:切面類的名稱,
ref:引用哪個bean(需要使用<bean>標籤初始化)-->
<aop:aspectid="logAspect"ref="logInterceptor">
<!-- 在此處定義的pointcut是全域性的pointcut只供當前的aspect使用
id:表示這個pointcut的名稱,以方便使用-->
<aop:pointcutid="myMethod2"
expression="execution(public * com.wjt276.service..*.*(..))"/>
<!--
定義advice時的引數
method:切面邏輯的方法名稱(切面類中的方法名)
pointcut-ref:表示引用哪個pointcut(要求已經在上面定義好了)
pointcut:定義一個pointcut -->
<aop:beforemethod="before"pointcut-ref="myMethod"/>
<aop:after-returningmethod="afterReturning"pointcut="execution(public * com.wjt276.service..*.*(..))"/>
</aop:aspect>
</aop:config>
</beans>
三、AOP實現動態代理注意因為Spring要實現AOP(面向切面程式設計),需要加入切面邏輯的類就會生成動態代理。在動態代理類中加入切面類從而實現面向切面程式設計,但生成動態代理存在以下注意事項:
1、被動態代理的類如果實現了某一個介面,那麼Spring就會利用JDK類庫生成動態代理。
2、如果被動態代理的類沒有實現某一個介面,那麼Spring就會利用CGLIB類庫直接修改二進位制碼來生成動態代理(因為利用JDK生成動態代理的類必須實現一個介面),需要在專案中引用CGLIB類庫