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>
最终两种方法的结果都是一样