Spring AOP详细介绍

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中配置下面一句:

<aop:aspectj-autoproxy />

2.通知类型介绍

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

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

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

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

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

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

3.例子:

(1)切面类

@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)目标对象和方法

@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) 配置以及测试

<context:component-scan base-package="com.aijava.springcode"/>
<aop:aspectj-autoproxy />   


//测试类
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.切入点的定义和表达式

Pointcut 是指那些方法需要被执行"AOP",是由"Pointcut Expression"来描述的。 可以有下列方式来定义.多个定义通过 ( && || ! ) 的方式进行组合 

execution()
args()
this()
target()
within()
annotation()

其中execution用的最多的,其格式为: 

execution([modifiers-pattern] ret-type-pattern [declaring-type-pattern]     
name-pattern(param-pattern) [throws-pattern]) 

[] 代表可选 ret-type-pattern,name-pattern(param-pattern)是必须要有的 ret-type-pattern:指定返回类型, 可以为 * 表示任何返回值,全路径的类名等. name-pattern:指定方法名,代表所有, set -- 代表以set开头的所有方法. parameters pattern:指定方法参数(声明的类型),(..)代表所有参数,()代表一个参数,(,String)代表第一个参数为任何值,第二个为String类型. 

举例说明: 
任意公共方法的执行: 

execution(public * *(..))

任何一个以“set”开始的方法的执行: 

execution(* set*(..))

AccountService 接口的任意方法的执行: 

execution(* com.xyz.service.AccountService.*(..))

定义在service包里的任意方法的执行:

execution(* com.xyz.service..(..))

定义在service包和所有子包里的任意类的任意方法的执行:

execution(* com.xyz.service...(..))

定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行:

execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")

最靠近(..)的为方法名,靠近.(..))的为类名或者接口名,如上例的JoinPointObjP2.(..))

6、spring-aop注意事项:

1、类内部方法调用不生效

被代理对象自身内部调用被增强,不会生效,因为是target内部this方法调用,不会调用代理对象,导致拦截失败。

原理及解决方案参考如下: http://blog.csdn.net/dapinxiaohuo/article/details/52092447

 

springAop与aspectj的区别:

http://blog.csdn.net/qq_21050291/article/details/72523138

 

转载说明:

https://www.cnblogs.com/liuruowang/p/5711563.html

posted on 2017-12-11 15:53  岁月无痕之玻璃心  阅读(282)  评论(0)    收藏  举报