spring AOP

AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。

一 AOP的基本概念

(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知

(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用

(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around

(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

二 Spring AOP

Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。

三 基于注解的AOP配置方式

1.启用@AsjectJ支持

在applicationContext.xml中配置下面一句:


2.通知类型介绍

(1)Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可

(2)AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值

(3)AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名

来访问目标方法中所抛出的异常对象

(4)After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式

(5)Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint

3.例子:

(1)Operator.java –> 切面类

复制代码
@Component
@Aspect
public class Operator {

@Pointcut("execution(* com.aijava.springcode.service..*.*(..))")
public void pointCut(){}

@Before("pointCut()")
public void doBefore(JoinPoint joinPoint){
    System.out.println("AOP Before Advice...");
}

@After("pointCut()")
public void doAfter(JoinPoint joinPoint){
    System.out.println("AOP After Advice...");
}

@AfterReturning(pointcut="pointCut()",returning="returnVal")
public void afterReturn(JoinPoint joinPoint,Object returnVal){
    System.out.println("AOP AfterReturning Advice:" + returnVal);
}

@AfterThrowing(pointcut="pointCut()",throwing="error")
public void afterThrowing(JoinPoint joinPoint,Throwable error){
    System.out.println("AOP AfterThrowing Advice..." + error);
    System.out.println("AfterThrowing...");
}

@Around("pointCut()")
public void around(ProceedingJoinPoint pjp){
    System.out.println("AOP Aronud before...");
    try {
        pjp.proceed();
    } catch (Throwable e) {
        e.printStackTrace();
    }
    System.out.println("AOP Aronud after...");
}

}
复制代码
(2)UserService.java –> 定义一些目标方法

复制代码
@Service
public class UserService {

public void add(){
    System.out.println("UserService add()");
}

public boolean delete(){
    System.out.println("UserService delete()");
    return true;
}

public void edit(){
    System.out.println("UserService edit()");
    int i = 5/0;
}

}
复制代码
(3).applicationContext.xml


(4).Test.java

复制代码
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(“classpath:applicationContext.xml”);
UserService userService = (UserService) ctx.getBean(“userService”);
userService.add();
}
}
复制代码
上面是一个比较简单的测试,基本涵盖了各种增强定义。注意:做环绕通知的时候,调用ProceedingJoinPoint的proceed()方法才会执行目标方法。

4.通知执行的优先级

进入目标方法时,先织入Around,再织入Before,退出目标方法时,先织入Around,再织入AfterReturning,最后才织入After。

注意:Spring AOP的环绕通知会影响到AfterThrowing通知的运行,不要同时使用!同时使用也没啥意义。

5.切入点的定义和表达式

切入点表达式的定义算是整个AOP中的核心,有一套自己的规范

Spring AOP支持的切入点指示符:

(1)execution:用来匹配执行方法的连接点

A:@Pointcut(“execution(* com.aijava.springcode.service...(..))”)

第一个表示匹配任意的方法返回值,..(两个点)表示零个或多个,上面的第一个..表示service包及其子包,第二个表示所有类,第三个*表示所有方法,第二个..表示

方法的任意参数个数

B:@Pointcut(“within(com.aijava.springcode.service.*)”)

within限定匹配方法的连接点,上面的就是表示匹配service包下的任意连接点

C:@Pointcut(“this(com.aijava.springcode.service.UserService)”)

this用来限定AOP代理必须是指定类型的实例,如上,指定了一个特定的实例,就是UserService

D:@Pointcut(“bean(userService)”)

bean也是非常常用的,bean可以指定IOC容器中的bean的名称

6.基于XML形式的配置方式

开发中如果选用XML配置方式,通常就是POJO+XML来开发AOP,大同小异,无非就是在XML文件中写切入点表达式和通知类型

例子:

(1)Log.java

复制代码
public class Log {

private Integer id;

//操作名称,方法名
private String operName;

//操作人
private String operator;

//操作参数
private String operParams;

//操作结果 成功/失败
private String operResult;

//结果消息
private String resultMsg;

//操作时间
private Date operTime = new Date();

setter,getter

}
复制代码
(2).Logger.java

复制代码
/**
* 日志记录器 (AOP日志通知)
*/
public class Logger {

@Resource
private LogService logService;

public Object record(ProceedingJoinPoint pjp){

    Log log = new Log();
    try {
        log.setOperator("admin");
        String mname = pjp.getSignature().getName();
        log.setOperName(mname);

        //方法参数,本例中是User user
        Object[] args = pjp.getArgs();
        log.setOperParams(Arrays.toString(args));

        //执行目标方法,返回的是目标方法的返回值,本例中 void
        Object obj = pjp.proceed();
        if(obj != null){
            log.setResultMsg(obj.toString());
        }else{
            log.setResultMsg(null);
        }

        log.setOperResult("success");
        log.setOperTime(new Date());

        return obj;
    } catch (Throwable e) {
        log.setOperResult("failure");
        log.setResultMsg(e.getMessage());
    } finally{
        logService.saveLog(log);
    }
    return null;
}

}
复制代码
(3).applicationContext.xml

复制代码


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值