时间:2017-2-4 21:12

——AspectJ简介

1、AspectJ是一个基于Java语言的AOP框架。
2、Spring2.0以后新增了对AspectJ切点表达式的支持。
3、@AspectJ是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面。

4、新版本Spring框架,建议使用AspectJ方式来开发AOP。
5、使用AspectJ需要导入Spring AOP和AspectJ相关jar包:
    spring-aop-3.2.0.RELEASE.jar

    com.springsource.org.aopalliance-1.0.0.jar
 
    spring-aspects-3.2.0.RELEASE.jar
    com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
 

——通过配置启用@AspectJ切面

<?xml version="1.0" encoding="UTF-8"?>
    <!-- 开启AspectJ自动代理-->
    <!-- 底层基于AnnotationAwareAspectJAutoProxyCreator,如果存在注解,则自动生成代理 -->
    <aop:aspectj-autoproxy />

</beans>
 

——在通知中通过value属性定义切点

1、通过execution函数,可以定义切点的方法切入
2、语法:
    execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
3、例如
    1)匹配所有类public方法:execution(public * *(..))
    2)匹配指定包下所有类方法:execution(* cn.itcast.dao.*(..)) 不包含子包
    3)execution(* cn.itcast.dao..*(..))  ..*表示包、子孙包下所有类
    4)匹配指定类所有方法:execution(* cn.itcast.service.UserService.*(..))
    5)匹配实现特定接口所有类方法,包含子类:execution(* cn.itcast.dao.GenericDAO+.*(..))
    6)匹配所有save开头的方法:execution(* save*(..))
 

——基于注解的开发

1、导包
    *   AspectJ依赖AOP环境。
        >    spring-aop-3.2.0.RELEASE.jar

        >   com.springsource.org.aopalliance-1.0.0.jar
 

*   导入AspectJ的jar包
        >   spring-aspects-3.2.0.RELEASE.jar
        >   com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

2、编写目标类
    UserDao
    提供增删改查方法。

3、使用AspectJ添加注解

    /**
     * 切面类
     * 切点 + 增强的结合
     * @author WYC
     *
     */
    // 用来定义切面类
    @Aspect
    public class MyAspect {
        // 对UserDao类的add()方法应用前置增强
        @Before(value = "execution(* com.wyc.spring3.demo1.UserDao.add())")
        public void before(){
            System.out.println("前置增强");
        }
    }

4、创建applicationContext.xml
    1)引入AOP的约束
    2)打开标签:<aop:aspectj-autoproxy />
        表示自动生成代理,该标签底层基于AnnotationAwareAspectJAutoProxyCreator,如果存在注解,则自动生成代理。


       <!-- 开启AspectJ自动代理 -->
        <!-- 底层基于AnnotationAwareAspectJAutoProxyCreator,如果存在注解,则自动生成代理 -->
        <aop:aspectj-autoproxy />
 
 
        <!-- 配置目标类 -->
        <bean id="userDao" class="com.wyc.spring3.demo1.UserDao" />
 
        <!-- 配置切面类(增强类) -->
        <bean id="myAspect" class="com.wyc.spring3.demo1.MyAspect" />

5、示例代码

UserDao目标类:

public class UserDao {
    public void add() {
        System.out.println("添加用户");
    }
 
    public void update() {
        System.out.println("修改用户");
    }
 
    public void delete() {
        System.out.println("删除用户");
    }
 
    public void find() {
        System.out.println("查询用户");
    }
}

----------------------------------------------------------------------------------------------------------------------------

MyAspect切面类:

/**
 * 切面类
 * 切点 + 增强的结合
 * @author WYC
 *
 */
// 用来定义切面类
@Aspect
public class MyAspect {
    // 对UserDao类的add()方法应用前置增强
    @Before(value = "execution(* com.wyc.spring3.demo1.UserDao.add())")
    // JoinPoint表示切点方法的描述,打印结果为:execution(void com.wyc.spring3.demo1.UserDao.add())
    public void before(JoinPoint joinPoing){
        System.out.println("前置增强" + joinPoing);
    }
}

----------------------------------------------------------------------------------------------------------------------------

XML配置文件:

<?xml version="1.0" encoding="UTF-8"?>
    xsi:schemaLocation="
 
    <!-- 开启AspectJ自动代理 -->
    <!-- 底层基于AnnotationAwareAspectJAutoProxyCreator,如果存在注解,则自动生成代理 -->
    <aop:aspectj-autoproxy />
 
    <!-- 配置目标类 -->
    <bean id="userDao" class="com.wyc.spring3.demo1.UserDao" />
 
    <!-- 配置增强类 -->
    <bean id="myAspect" class="com.wyc.spring3.demo1.MyAspect" />
 
</beans>

----------------------------------------------------------------------------------------------------------------------------

测试代码:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo1 {
 
    @Autowired
    @Qualifier("userDao")
    private UserDao userDao;
 
    @Test
    public void fun1(){
        userDao.add();
        userDao.delete();
        userDao.update();
        userDao.find();
    }
}

——AspectJ的通知类型

1、@Before 前置通知,相当于BeforeAdvice
    在目标方法之前执行,前置通知无法阻止目标对象执行。 
 
2、@AfterReturning 后置通知,相当于AfterReturningAdvice
    后置通知可以获得方法的返回值。 
 
3、@Around 环绕通知,相当于MethodInterceptor
    可以在方法执行前后执行增强方法,环绕通知可以阻止目标方法执行,可以得到目标方法的返回值。 
 
4、@AfterThrowing抛出通知,相当于ThrowAdvice
    当抛出异常时,会执行该通知。
 
5、@After 最终final通知,不管是否异常,该通知都会执行
 
6、@DeclareParents 引介通知,相当于IntroductionInterceptor (不要求掌握)

示例代码:

UserDao目标类:

public class UserDao {
    public void add() {
        System.out.println("添加用户");
    }
 
    public int update() {
        System.out.println("修改用户");
        return 123;
    }
 
    public void delete() {
        System.out.println("删除用户");
    }
 
    public void find() {
        System.out.println("查询用户");
        throw new RuntimeException("哈哈哈");
    }
}

----------------------------------------------------------------------------------------------------------------------------

MyAspect切面类:

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;
 
/**
 * 切面类
 * 切点 + 增强的结合
 * @author WYC
 *
 */
// 用来定义切面类
@Aspect
public class MyAspect {
    // 对UserDao类的add()方法应用前置增强
    @Before(value = "execution(* com.wyc.spring3.demo1.UserDao.add())")
    public void before(JoinPoint joinPoing){
        System.out.println("前置增强..." + joinPoing);
    }
 
 
    // 后置通知
    @AfterReturning(value="execution(* com.wyc.spring3.demo1.UserDao.update(..))", returning="returnVal")
    // 参数名必须和注解中的配置相同,returnVal会得到方法执行后的返回值
    public void afterReturing(Object returnVal){
        System.out.println("后置增强... " + returnVal);
    }
 
 
    // 环绕通知
    @Around(value = "execution(* com.wyc.spring3.demo1.UserDao.find(..))")
    // ProceedingJoinPoint,获得切点方法
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("环绕前增强...");
 
        // 调用目标方法,该方法会返回目标方法的返回值
        Object obj = proceedingJoinPoint.proceed();
        System.out.println("环绕后增强...");
        return obj;
    }
 
 
    // 异常通知,throwing="e"表示获取一场对象,e表示异常对象的名称
    @AfterThrowing(value="execution(* com.wyc.spring3.demo1.UserDao.find())", throwing="e")
    public void afterThrowing(Throwable e){
        // 显示异常信息
        System.out.println("抛出异常... " + e.getMessage());
    }
 
 
    // 最终通知
    @After(value="execution(* com.wyc.spring3.demo1.UserDao.*())")
    public void after(){
        System.out.println("最终通知....");
    }

}

----------------------------------------------------------------------------------------------------------------------------

XML配置文件:

<?xml version="1.0" encoding="UTF-8"?>
    xsi:schemaLocation="
 
    <!-- 开启AspectJ自动代理 -->
    <!-- 底层基于AnnotationAwareAspectJAutoProxyCreator,如果存在注解,则自动生成代理 -->
    <aop:aspectj-autoproxy />
 
    <!-- 配置目标类 -->
    <bean id="userDao" class="com.wyc.spring3.demo1.UserDao" />
    <!-- 配置增强类 -->
    <bean id="myAspect" class="com.wyc.spring3.demo1.MyAspect" />
 
</beans>

---------------------------------------------------------------------------------------------------------------------------- 

测试代码:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo1 {
 
    @Autowired
    @Qualifier("userDao")
    private UserDao userDao;
 
    @Test
    public void fun1(){
        userDao.add();
        userDao.delete();
        userDao.update();
        userDao.find();
    }
}

---------------------------------------------------------------------------------------------------------------------------- 

打印结果:

前置增强...execution(void com.wyc.spring3.demo1.UserDao.add())
添加用户
最终通知....
删除用户
最终通知....
修改用户
最终通知....
后置增强... 123
环绕前增强...
查询用户
最终通知....
抛出异常... 哈哈哈

——切点的注解

定义一个方法,添加注解表达式,然后在其他方法的注解中使用:类名.方法  即可。

示例代码:

/**
 * 切面类
 * 切点 + 增强的结合
 * @author WYC
 *
 */
// 用来定义切面类
@Aspect
public class MyAspect {
    // 对UserDao类的add()方法应用前置增强
    @Before(value = "execution(* com.wyc.spring3.demo1.UserDao.add())")
    public void before(JoinPoint joinPoing){
        System.out.println("前置增强..." + joinPoing);
    }
 
    // 后置通知
    @AfterReturning(value="execution(* com.wyc.spring3.demo1.UserDao.update(..))", returning="returnVal")
    // 参数名必须和注解中的配置相同
    public void afterReturing(Object returnVal){
        System.out.println("后置增强... " + returnVal);
    }
 
    // 环绕通知
    @Around(value = "MyAspect.myPointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("环绕前增强...");
 
        // 调用目标方法
        Object obj = proceedingJoinPoint.proceed();
        System.out.println("环绕后增强...");
        return obj;
    }
 
    // 异常通知
    @AfterThrowing(value="MyAspect.myPointcut()", throwing="e")
    public void afterThrowing(Throwable e){
        // 显示异常信息
        System.out.println("抛出异常... " + e.getMessage());
    }
 
    // 最终通知
    @After("MyAspect.myPointcut()")
    public void after(){
        System.out.println("最终通知....");
    }
 
    /*
     * 定义一个通用的表达式
     */
    @Pointcut("execution(* com.wyc.spring3.demo1.UserDao.find())")
    private void myPointcut(){
 
    }
}

——Advisor和Aspect的区别

1、Advisor:Spring传统意义上的切面,支持一个切点和一个通知的组合。
2、Aspect:可以支持多个切点和多个通知的组合。 

——基于XML的开发

1、编写被增强的类:

    *   ProductDao

2、定义切面

3、配置applicationContext.xml
    1)前置通知:
        代码:
            public void before(){
                System.out.println("前置通知...");
            }
        配置:

            <!-- 定义AOP配置 -->
            <aop:config>
                <!-- 定义切点 -->
                <!-- 前置通知 -->
                <!-- 给指定表达式起名 -->
                <aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.add(..))" id="beforePointcut"/>
 
                <!-- 定义切面 -->
                <aop:aspect ref="myAspectXML">
                    <!-- 给切面类的指定方法添加表达式 -->
                    <!-- 前置通知 -->
                    <aop:before method="before" pointcut-ref="beforePointcut"/>
                </aop:aspect>
            </aop:config>

2)后置通知
        代码:
            public void afterReturning(Object returnVal){

                System.out.println("后置增强... " + returnVal);
            }

配置:
            <!-- 定义AOP配置 -->

            <aop:config>
                <!-- 定义切点 -->
                <!-- 给指定表达式起名 -->
                <aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.find(..))" id="afterReturning"/>

 
                <!-- 定义切面 -->
                <aop:aspect ref="myAspectXML">
                    <!-- 给切面类的指定方法添加表达式 -->
                    <!-- 后置通知 -->
                    <aop:after-returning method="afterReturning" pointcut-ref="afterReturning" returning="returnVal"/>
                </aop:aspect>
            </aop:config>

3)环绕通知
        代码:
            public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{

                System.out.println("环绕前增强...");
                Object result = proceedingJoinPoint.proceed();
                System.out.println(result);
                System.out.println("环绕后增强...");
                return result;
            }

配置:
            <!-- 定义AOP配置 -->

            <aop:config>
                <!-- 定义切点 -->
                <!-- 给指定表达式起名 -->
                <aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.delete(..))" id="myPointcut"/>

 
                <!-- 定义切面 -->
                <aop:aspect ref="myAspectXML">
                    <!-- 给切面类的指定方法添加表达式 -->
                    <!-- 环绕通知 -->
                    <aop:around method="around" pointcut-ref="myPointcut"/>
                </aop:aspect>
            </aop:config>

4)异常通知
        代码:
            public void afterThrowing(Throwable e){

                System.out.println("异常通知..." + e.getMessage());
            }

配置:
            <!-- 定义AOP配置 -->

            <aop:config>
                <!-- 定义切点 -->
                <!-- 给指定表达式起名 -->
                <aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.update(..))" id="afterThrowing"/>

 
                <!-- 定义切面 -->
                <aop:aspect ref="myAspectXML">
                    <!-- 异常通知 -->
                    <aop:after-throwing method="afterThrowing" pointcut-ref="afterThrowing" throwing="e"/>
                </aop:aspect>
            </aop:config>

5)最终通知
        代码:
            public void after(){

                System.out.println("最终通知...");
            }
 

配置:
            <aop:config>

                <!-- 定义切点 -->
                <!-- 给指定表达式起名 -->
                <aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.update(..))" id="afterThrowing"/>

 
                <!-- 定义切面 -->
                <aop:aspect ref="myAspectXML">
                    <!-- 最终通知 -->
                    <aop:after method="after" pointcut-ref="afterThrowing"/>
                </aop:aspect>
            </aop:config>

4、示例代码

ProductDao目标类:

public class ProductDao {
    public void add() {
    System.out.println("添加商品");
}
 
public void update() {
    System.out.println("修改商品");
    // throw new RuntimeException("哈哈哈哈哈");
}
 
public Object delete() {
    System.out.println("删除商品");
    return "删除成功";
}
 
public int find() {
    System.out.println("查询商品");
    return 123;
}

------------------------------------------------------------------------------------------------------------------

MyAspectXML切面类:

import org.aspectj.lang.ProceedingJoinPoint;
 
/**
 * 切面类
 * 
 * @author WYC
 * 
 */
public class MyAspectXML {
    // 前置通知
    public void before() {
        System.out.println("前置增强...");
    }
 
    // 后置通知
    public void afterReturning(Object returnVal) {
        System.out.println("后置增强... " + returnVal);
    }
 
    // 环绕通知
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前增强...");
        Object result = proceedingJoinPoint.proceed();
        System.out.println(result);
        System.out.println("环绕后增强...");
        return result;
    }
 
    // 异常通知
    public void afterThrowing(Throwable e) {
        System.out.println("异常通知..." + e.getMessage());
    }
 
    // 最终通知
    public void after() {
        System.out.println("最终通知...");
    }
}

------------------------------------------------------------------------------------------------------------------

applicationContext.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
    xsi:schemaLocation="
 
    <!-- 定义目标类 -->
    <bean id="productDao" class="com.wyc.spring3.demo2.ProductDao" />
 
    <!-- 定义切面类 -->
    <bean id="myAspectXML" class="com.wyc.spring3.demo2.MyAspectXML" />
 
    <!-- 定义AOP配置 -->
    <aop:config>
        <!-- 定义切点 -->
        <!-- 前置通知 -->
        <!-- 给指定表达式起名 -->
        <aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.add(..))" id="beforePointcut"/>
        <aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.*(..))" id="afterReturning"/>
        <aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.delete(..))" id="myPointcut"/>
        <aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.update(..))" id="afterThrowing"/>
 
        <!-- 定义切面 -->
        <aop:aspect ref="myAspectXML">
            <!-- 给切面类的指定方法添加表达式 -->
            <!-- 前置通知 -->
            <aop:before method="before" pointcut-ref="beforePointcut"/>
 
            <!-- 后置通知 -->
            <aop:after-returning method="afterReturning" pointcut-ref="afterReturning" returning="returnVal"/>
 
            <!-- 环绕通知 -->
            <aop:around method="around" pointcut-ref="myPointcut"/>
 
            <!-- 异常通知 -->
            <aop:after-throwing method="afterThrowing" pointcut-ref="afterThrowing" throwing="e"/>
 
            <!-- 最终通知 -->
            <aop:after method="after" pointcut-ref="afterThrowing"/>
        </aop:aspect>
    </aop:config>
 
</beans>

------------------------------------------------------------------------------------------------------------------

测试代码:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class SpringDemo2 {
  @Autowired
  @Qualifier("productDao")
  private ProductDao productDao;
 
  @Test
  public void fun1() {
    productDao.add();
    productDao.update();
    productDao.delete();
    productDao.find();
  }
}

——总结

为了简化开发,引入了AspectJ的支持。

1、基于注解开发
    开启XML中支持AOP的配置。

    @Aspect:切面注解

    @Before:前置通知
    @Around:环绕通知
    @AfterReturing:后置通知
    @AfterThrowing:抛出异常通知
    @After:最终通知

    @Pointcut:切点注解
        可以简化开发,不需要每一个注解都写表达式。

2、基于XML开发
    1)引入AOP的名称空间。
    2)<aop-config>
            <!-- 定义切点 -->
            <aop:pointcut id="" expression="" />

            <!-- 定义切面,并引入切点 -->
            <aop:aspect ref="">
                <aop:brfore />
            </aop:aspect>
          </aop-config>

Spring之AspectJ的更多相关文章

  1. Spring AOP + AspectJ annotation example

    In this tutorial, we show you how to integrate AspectJ annotation with Spring AOP framework. In simp ...

  2. Spring AOP + AspectJ Annotation Example---reference

    In this tutorial, we show you how to integrate AspectJ annotation with Spring AOP framework. In simp ...

  3. Spring 使用AspectJ的三种方式

    Spring 使用AspectJ 的三种方式 一,使用JavaConfig 二,使用注解隐式配置 三,使用XML 配置 背景知识: 注意 使用AspectJ 的 时候 要导入相应的Jar 包 嗯 昨天 ...

  4. Spring学习之旅(八)Spring 基于AspectJ注解配置的AOP编程工作原理初探

    由小编的上篇博文可以一窥基于AspectJ注解配置的AOP编程实现. 本文一下未贴出的相关代码示例请关注小编的上篇博文<Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AO ...

  5. 学习 Spring (十七) Spring 对 AspectJ 的支持 (完结)

    Spring入门篇 学习笔记 @AspectJ 的风格类似纯 java 注解的普通 java 类 Spring 可以使用 AspectJ 来做切入点解析 AOP 的运行时仍旧是纯的 Spring AO ...

  6. 关于 Spring AOP (AspectJ) 该知晓的一切

    关联文章: 关于Spring IOC (DI-依赖注入)你需要知道的一切 关于 Spring AOP (AspectJ) 你该知晓的一切 本篇是年后第一篇博文,由于博主用了不少时间在构思这篇博文,加上 ...

  7. Spring学习(十八)----- Spring AOP+AspectJ注解实例

    我们将向你展示如何将AspectJ注解集成到Spring AOP框架.在这个Spring AOP+ AspectJ 示例中,让您轻松实现拦截方法. 常见AspectJ的注解: @Before – 方法 ...

  8. Spring结合AspectJ的研究

    本文阐述以下内容:1.AspectJ是什么及使用方式2.Spring AOP和AspectJ的区别3.Spring结合AspectJ的使用方法和原理4.Spring注解方式使用AspectJ遇到的问题 ...

  9. 10 Spring框架 AOP (三) Spring对AspectJ的整合

    上两节我们讲了Spring对AOP的实现,但是在我们的开发中我们不太使用Spring自身的对AOP的实现,而是使用AspectJ,AspectJ是一个面向切面的框架,它扩展了Java语言.Aspect ...

  10. Spring整合AspectJ的AOP

    学而时习之,不亦说乎!                              --<论语> 看这一篇之前最好先看前面关于AOP的两篇. http://www.cnblogs.com/z ...

随机推荐

  1. 【LeetCode】27.移除元素

    27.移除元素 知识点:数组:双指针:: 题目描述 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度. 不要使用额外的数组空间,你必须 ...

  2. debian 9 pycharm安装

    官网下载PyCharm的tar.gz格式 使用命令进行解压:tar -xvzf pycharm.tar.gz 解压后将pycharm文件夹移动到/usr/local/lib/目录下 进入pycharm ...

  3. tomcat内置jdk(tomcat集成jdk)(windows环境)

    tomcat内置jdk,步骤: 1.在一个已经安装了jdk或者jre的机器上,拷贝一个jre到tomcat根目录下. 2.编辑tomcat/bin文件夹下的catalina.bat文件,在文件开头加上 ...

  4. javascript学习--(四)面向对象:

    一.生成器generator: javascript里的generator函数是用function*定义的, 案例:yield 也会返回 function* foo(x){ yield x+1; yi ...

  5. Github上比较全的学习路线

    github地址:https://github.com/kamranahmedse/developer-roadmap/blob/master/translations/chinese

  6. CC2B本地环境搭建步骤及部署问题解决

    由于最近的项目是之前没接触过的netbeans+glassfish,记录一下最近在工作中搭建本地环境的步骤及遇到的一些问题解决方法: 1.配置java jdk 此过程中遇到一个问题就是在配置系统环境变 ...

  7. mysql查看当前连接数

    show status like 'Threads%';   需要root权限才能看到所有的连接

  8. 用python将word转pdf、doc转docx等

    word ==> pdf def doc2pdf(file_path): """ word格式转换doc|docx ==> pdf :return: &quo ...

  9. Centos8 Nginx 开机自启配

    第一步:创建 service文件 vim /lib/systemd/system/nginx.service /lib 与 /usr/lib 我这里配置时是一样的,在那个文件夹配置都可以 第二步:编写 ...

  10. 打造自己的Vue组件文档生成工具

    程序员最讨厌的两件事情,第一种是写文档,另一种是别人没有写文档.有没有直接根据vue组件生成文档的呢?当然是有的的.但第三方使用起来不一定能和现有项目结合使用,往往需要额外的注释用来标记提取信息.使用 ...