Spring AOP
AspectJ:(Java社区里最完整最流行的AOP框架)
spring自身也有一套AOP框架,但相比较于AspectJ,更推荐AspectJ
在Spring2.0以上版本中,可以使用基于AspectJ注解或基于XML配置的AOP。
基于AspectJ注解:
用AspectJ注解声明切面
要在Spring中声明AspectJ切面,只需要在IOC容器中将切面声明为Bean实例,当在Spring IOC容器中初始化AspectJ切面之后,
要在Spring中声明AspectJ切面,只需要在IOC容器中将切面声明为Bean实例,当在Spring IOC容器中初始化AspectJ切面之后,
Spring IOC容器就会为为那些与AspectJ切面相匹配的Bean创建代理。
在 AspectJ注解中,切面只是 一个带有@AspectJ注解的Java类。
通知是标注有某种注解的的简单的java方法
AspectJ支持5种类型的通知注解:
-@Before 前置通知,在目标方法执行之前执行
-@After:后置通知:在目标方法执行之后执行,无论是否发生异常
-@AfterReturning:返回通知,在目标方法返回结果之后执行
-@AfterThrowing:异常通知,在目标方法抛出异常之后通知。
-@Around 环绕通知,围绕着目标方法执行。
-@After:后置通知:在目标方法执行之后执行,无论是否发生异常
-@AfterReturning:返回通知,在目标方法返回结果之后执行
-@AfterThrowing:异常通知,在目标方法抛出异常之后通知。
-@Around 环绕通知,围绕着目标方法执行。
基于AspectJ注解添加前置通知步骤:
1)加入jar包
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
commons-logging-1.1.3.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
2)在配置文件中加入aop和context的命名空间
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
3)基于注解的方式
1.在配置文件里加入如下配置:
- <!-- 配置自动扫描的包 -->
- <context:component-scan base-package="com.wul.spring.aop.impl"></context:component-scan>
- <!-- 使AspectJ注解起作用:自动为匹配的类生成代理对象 -->
- <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
2.声明一个切面的类并把横切关注点代码抽象到切面的类中:
I.切面首先是一个IOC中的bean,即加入@Component注释
II.切面还需要加入@Aspect
3.在类中声明各种通知
I.声明一个方法II.在方法前加入@Before注解
III.利用方法签名编写AspectJ切入点表达式
关于方法签名编写的切点表达式:
1.execution (
*com.wul.spring.aop.impl.AtithmeticCalculator.
*(..))
匹配 ArithmeticCalculator 中声明的所有方法,
第一个 * 代表任意修饰符及任意返回值.
第二个 * 代表任意方法.
..
匹配任意数量的参数.
若目标类与接口与该切面在同一个包中, 可以省略包名.
2.execution (
public * ArithmeticCalculator.*(..))
匹配 ArithmeticCalculator 接口的
所有公有方法.
3.execution(* * , *()..)
第
一个 *代表匹配任意修饰符及任意返回值
,
第二个 * 代表任意类的对象
,
第三个 *代表任意方法
,
参数列表中的
..
匹配任意数量的参数.
4.在 AspectJ 中, 切入点表达式可以通过操作符 &&, ||, ! 结合起来.
5.可以在通知方法中声明一个类型为 JoinPoint 的参数. 然后就能访问链接细节. 如方法名称和参数值.
public void beforeMethod(JoinPoint joinPoint)
方法名:String methodName = joinPoint.getSignature().getName();
参数值:List<Object> args = Arrays.asList(joinPoint.getArgs());
前置通知:
- //声明该方法是一个前置通知:在目标方法开始之前执行
- / @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.add(int ,int))")
- @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))")
- public void beforeMethod(JoinPoint joinPoint){
- String methodName = joinPoint.getSignature().getName();
- List<Object> args = Arrays.asList(joinPoint.getArgs());
- System.out.println("The method "+methodName +" begins with "+ args);
- }
- //后置通知:在目标方法之后(无论是否发生异常),执行的通知,
- //在后置通知中还不能访问目标方法执行的结果。执行结果须在返回通知中访问。
- @After("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))")
- public void afterMethod(JoinPoint joinPoint){
- String methodName = joinPoint.getSignature().getName();
- System.out.println("The method "+ methodName+" ends");
- }
返回通知:
- //返回通知:在目标方法正常结束执行后的通知
- //返回通知是可以访问到目标方法的返回值的
- @AfterReturning(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))"
- , returning = "result")
- public void afterRunningMethod(JoinPoint joinPoint , Object result){
- String methodName = joinPoint.getSignature().getName();
- System.out.println("The method "+ methodName+" ends with the Result "+ result);
- }
异常通知:
- //在目标方法出现异常时会执行的代码,
- //可以访问到异常对象,且可以指定在出现特定异常时在执行通知代码
- //如下面Exception ex,若是指定为NullpointerException ex就不会执行通知代码
- @AfterThrowing(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))"
- , throwing="ex")
- public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
- String methodName = joinPoint.getSignature().getName();
- System.out.println("The method "+ methodName+"occurs exception:"+ex);
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- String methodName = method.getName();
- //日志
- System.out.println("The method "+methodName+" begin with "+Arrays.asList(args));
- //执行方法
- Object result = null;
- try{
- //前置通知
- result = method.invoke(target, args);
- //返回通知,可以访问到方法的返回通知
- }catch(Exception e){
- e.printStackTrace();
- //异常通知:可以访问到方法出现的异常
- }
- //后置通知:因为方法可能出错,所以访问不到方法的返回值。
- //日志
- System.out.println("The method "+methodName + " ends with "+result);
- return result;
- }
环绕通知:(类似于动态代理的过程)
- package com.wul.spring.aop.impl;
- import java.util.Arrays;
- import java.util.List;
- import org.aspectj.lang.JoinPoint;
- 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.springframework.stereotype.Component;
- //把这个类声明为一个切面:需要把该类放入到IOC容器中,再声明为一个切面
- @Aspect
- @Component
- public class LogginAspect {
- //声明该方法是一个前置通知:在目标方法开始之前执行
- // @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.add(int ,int))")
- @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))")
- public void beforeMethod(JoinPoint joinPoint){
- String methodName = joinPoint.getSignature().getName();
- List<Object> args = Arrays.asList(joinPoint.getArgs());
- System.out.println("The method "+methodName +" begins with "+ args);
- }
- //后置通知:在目标方法之后(无论是否发生异常),执行的通知,
- //在后置通知中还不能访问目标方法执行的结果。执行结果须在返回通知中访问。
- @After("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))")
- public void afterMethod(JoinPoint joinPoint){
- String methodName = joinPoint.getSignature().getName();
- System.out.println("The method "+ methodName+" ends");
- }
- //返回通知:在目标方法正常结束执行后的通知
- //返回通知是可以访问到目标方法的返回值的
- @AfterReturning(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))"
- , returning = "result")
- public void afterRunningMethod(JoinPoint joinPoint , Object result){
- String methodName = joinPoint.getSignature().getName();
- System.out.println("The method "+ methodName+" ends with the Result "+ result);
- }
- //在目标方法出现异常时会执行的代码,
- //可以访问到异常对象,且可以指定在出现特定异常时在执行通知代码
- //如下面Exception ex,若是指定为NullpointerException ex就不会执行通知代码
- @AfterThrowing(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))"
- , throwing="ex")
- public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
- String methodName = joinPoint.getSignature().getName();
- System.out.println("The method "+ methodName+"occurs exception:"+ex);
- }
- //坏绕通知:需要携带ProceedingJoinPoint类型的参数
- //环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法
- //且环绕通知必须有返回值,返回值即目标方法的返回值。
- @Around("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))")
- public Object aroundMethod(ProceedingJoinPoint pjd){
- Object result = null;
- String methodName = pjd.getSignature().getName();
- Object args = Arrays.asList(pjd.getArgs());
- //执行目标方法
- try {
- //前置通知
- System.out.println("Arround:The method "+methodName +" begins with "+ args);
- result = pjd.proceed();
- //后置通知
- System.out.println("Arround:The method "+ methodName+" ends");
- } catch (Throwable e) {
- e.printStackTrace();
- //异常通知
- System.out.println("Arround:The method "+ methodName+"occurs exception:"+e);
- //throw new RuntimeException(e);
- //不抛出异常的话,异常就被上面抓住,执行下去,返回result,result值为null,转换为int
- }
- //返回通知
- System.out.println("Arround:The method "+ methodName+" ends with the Result "+ result);
- //return 100;
- return result;
- }
- }
AtithmeticCalculator.java
- package com.wul.spring.aop.impl;
- public interface AtithmeticCalculator {
- int add(int i, int j);
- int sub(int i, int j);
- int mul(int i, int j);
- int div(int i, int j);
- }
AtithmeticCalculatorImpl.java
- package com.wul.spring.aop.impl;
- import org.springframework.stereotype.Component;
- @Component
- public class AtithmeticCalculatorImpl implements AtithmeticCalculator {
- @Override
- public int add(int i, int j) {
- int result = i + j;
- return result;
- }
- @Override
- public int sub(int i, int j) {
- int result = i - j;
- return result;
- }
- @Override
- public int mul(int i, int j) {
- int result = i * j;
- return result;
- }
- @Override
- public int div(int i, int j) {
- int result = i / j;
- return result;
- }
- }
LogginAspect.java
- package com.wul.spring.aop.impl;
- import java.util.Arrays;
- import java.util.List;
- import org.aspectj.lang.JoinPoint;
- 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.springframework.stereotype.Component;
- //把这个类声明为一个切面:需要把该类放入到IOC容器中,再声明为一个切面
- @Aspect
- @Component
- public class LogginAspect {
- //声明该方法是一个前置通知:在目标方法开始之前执行
- // @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.add(int ,int))")
- @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))")
- public void beforeMethod(JoinPoint joinPoint){
- String methodName = joinPoint.getSignature().getName();
- List<Object> args = Arrays.asList(joinPoint.getArgs());
- System.out.println("The method "+methodName +" begins with "+ args);
- }
- //后置通知:在目标方法之后(无论是否发生异常),执行的通知,
- //在后置通知中还不能访问目标方法执行的结果。执行结果须在返回通知中访问。
- @After("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))")
- public void afterMethod(JoinPoint joinPoint){
- String methodName = joinPoint.getSignature().getName();
- System.out.println("The method "+ methodName+" ends");
- }
- //返回通知:在目标方法正常结束执行后的通知
- //返回通知是可以访问到目标方法的返回值的
- @AfterReturning(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))"
- , returning = "result")
- public void afterRunningMethod(JoinPoint joinPoint , Object result){
- String methodName = joinPoint.getSignature().getName();
- System.out.println("The method "+ methodName+" ends with the Result "+ result);
- }
- //在目标方法出现异常时会执行的代码,
- //可以访问到异常对象,且可以指定在出现特定异常时在执行通知代码
- //如下面Exception ex,若是指定为NullpointerException ex就不会执行通知代码
- @AfterThrowing(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))"
- , throwing="ex")
- public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
- String methodName = joinPoint.getSignature().getName();
- System.out.println("The method "+ methodName+"occurs exception:"+ex);
- }
- //坏绕通知:需要携带ProceedingJoinPoint类型的参数
- //环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法
- //且环绕通知必须有返回值,返回值即目标方法的返回值。
- @Around("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))")
- public Object aroundMethod(ProceedingJoinPoint pjd){
- Object result = null;
- String methodName = pjd.getSignature().getName();
- Object args = Arrays.asList(pjd.getArgs());
- //执行目标方法
- try {
- //前置通知
- System.out.println("Arround:The method "+methodName +" begins with "+ args);
- result = pjd.proceed();
- //后置通知
- System.out.println("Arround:The method "+ methodName+" ends");
- } catch (Throwable e) {
- e.printStackTrace();
- //异常通知
- System.out.println("Arround:The method "+ methodName+"occurs exception:"+e);
- //throw new RuntimeException(e);
- //不抛出异常的话,异常就被上面抓住,执行下去,返回result,result值为null,转换为int
- }
- //返回通知
- System.out.println("Arround:The method "+ methodName+" ends with the Result "+ result);
- //return 100;
- return result;
- }
- }
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: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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
- <!-- 配置自动扫描的包 -->
- <context:component-scan base-package="com.wul.spring.aop.impl"></context:component-scan>
- <!-- 使AspectJ注解起作用:自动为匹配的类生成代理对象 -->
- <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- </beans>
Main.java
- package com.wul.spring.aop.impl;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class Main {
- public static void main(String[] args) {
- //1.创建Spring的IOC容器
- ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
- //2.从IOC容器中获取bean的实例
- AtithmeticCalculator arithmeticCalculator = ctx.getBean(AtithmeticCalculator.class);
- //3.使用bean
- int result = arithmeticCalculator.add(3,6);
- System.out.println("result: "+result);
- result = arithmeticCalculator.div(10,5);
- System.out.println("result: "+result);
- result = arithmeticCalculator.div(10,0);
- }
- }