Spring AOP概述及使用
AOP概述
AOP面向切面程式設計(Aspect Oriented Programming)
通過預編譯方式和執行期動態代理實現程式功能的統一維護的一種技術。
常用於日誌記錄,效能統計,安全控制,事務處理,異常處理等
AOP術語
JoinPoint 連線點(切入點)
PointCut 連線點集合
Aspect(切面)
Advice(通知)
Target(織入到的方法)
Weave(織入)
Aspectj切入點表示式
execution(public * *(..)) 任何類的任何返回值的任何方法
execution(* set*(..)) 任何類的set開頭的方法
execution(* com.yinghuo.service.AccountService.*(..)) 任何返回值的規定類裡面的方法
execution(* com.yinghuo.service..*.*(..)) 任何返回值的,規定包或者規定包子包的任何類任何方法
Aspectj的Advice(面向方面程式設計的通知)
@Before 方法執行之前
@After 方法執行之後
@ AfterReturning 方法正常執行完後執行
@ AfterThrowing 丟擲異常時執行
@Around 前後都可以加邏輯
Spring AOP使用
首先要匯入spring-aspects的jar包才可以
佈局如圖
註解實現
UserService介面
package cn.yinghuo.service;
public interface UserService {
public void save();
}
UserServiceImpl實現介面
package cn.yinghuo.service.impl; import org.springframework.stereotype.Component; import cn.yinghuo.service.UserService; @Component public class UserServiceImpl implements UserService{ @Override public void save() { System.out.println("Howie"); } }
測試類
package cn.yinghuo.action;
import javax.annotation.Resource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import cn.yinghuo.service.UserService;
@Component("mainaction")
public class MainAction {
UserService userService;
public void save(){
userService.save();
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
MainAction mAction = (MainAction)context.getBean("mainaction");
mAction.save();
}
public UserService getUserService() {
return userService;
}
@Resource
public void setUserService(UserService userService) {
this.userService = userService;
}
}
ApplicationContext.xml配置
<?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
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-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
">
<context:annotation-config/>
<!-- 配置cn.yinghuo下全部包 -->
<context:component-scan base-package="cn.yinghuo.*"></context:component-scan>
<!-- 開啟代理配置 -->
<aop:aspectj-autoproxy/>
</beans>
執行一下控制檯輸出結果Howie,接下來加上Aspectj的Advice(面向方面程式設計的通知)
AopModel類
package cn.yinghuo.aop;
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;
@Aspect
@Component
public class AopModel {
//定義
@Pointcut("execution(* cn.yinghuo.service..*.*(..))")
public void show(){
};
//可以用簡化過的空的show方法,也可以繼續用Aspectj切面表示式
//Aspectj織入點語法 execution(* com.xyz.service..*.*(..)) 任何返回值的,規定包或者規定包子包的任何類任何方法
//Aspectj的Advice
//@Before方法執行之前
@Before("show()")
public void before(){
System.out.println("@Before方法執行之前");
}
//@After方法執行之後
@After("execution(* cn.yinghuo.service..*.*(..))")
public void after(){
System.out.println("@After方法執行之後");
}
//@AfterReturning方法正常執行完後執行(如果前面方法沒有正常執行就不執行)
@AfterReturning("execution(* cn.yinghuo.service..*.*(..))")
public void afterReturning(){
System.out.println("@AfterReturning方法正常執行完後執行");
}
//@AfterThrowing丟擲異常時執行(如果沒有異常就不執行)
@AfterThrowing("execution(* cn.yinghuo.service..*.*(..))")
public void afterThrowing(){
System.out.println("@AfterThrowing丟擲異常時執行");
}
//@Around前後都可以加邏輯
@Around("execution(* cn.yinghuo.service..*.*(..))")
public void around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("@Around前");
pjp.proceed();
System.out.println("@Around後");
}
}
不存在異常時輸出結果為
@Around前
@Before方法執行之前
Howie
@Around後
@After方法執行之後
@AfterReturning方法正常執行完後執行
在UserServiceImpl實現接口裡寫一個異常
//除0異常
int a = 1;
int b = 0;
System.out.println(a/b);
再次執行
@Around前
@Before方法執行之前
Exception in thread "main" java.lang.ArithmeticException: / by zero
at cn.yinghuo.service.impl.UserServiceImpl.save(UserServiceImpl.java:17)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
at cn.yinghuo.aop.AopModel.around(AopModel.java:53)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618)Howie
@After方法執行之後
@AfterThrowing丟擲異常時執行
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:47)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy13.save(Unknown Source)
at cn.yinghuo.action.MainAction.save(MainAction.java:16)
at cn.yinghuo.action.MainAction.main(MainAction.java:22)
由此可看出@AfterThrowing在有異常時執行了,而@AfterReturning在有異常沒有執行而在正常情況下執行了,其它的Advice都不受異常的影響
XML實現
XML配置
<?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
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-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
">
<context:annotation-config/>
<!-- 配置cn.yinghuo下全部包 -->
<context:component-scan base-package="cn.yinghuo.*"></context:component-scan>
<!-- XML版AOP配置 -->
<bean id="aopmodel" class="cn.yinghuo.aop.AopModel"></bean>
<aop:config>
<aop:aspect id="aopmodel" ref="aopmodel">
<aop:pointcut expression="execution(* cn.yinghuo.service..*.*(..))" id="aopmodel2" />
<aop:before method="before" pointcut-ref="aopmodel2"/>
<aop:after method="after" pointcut-ref="aopmodel2"/>
<aop:after-returning method="afterReturning" pointcut-ref="aopmodel2"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="aopmodel2"/>
<aop:around method="around" pointcut-ref="aopmodel2"/>
</aop:aspect>
</aop:config>
</beans>
最終兩種方法的結果都是一樣