• Java Spring-AspectJ


    2017-11-10 21:25:02

    Spring的AspectJ的AOP
    AspectJ 是一个面向切面的框架,它扩展了 Java 语言。 AspectJ 定义了 AOP 语法所以它有一个专门的编译器用来生成遵守 Java 字节编码规范的 Class 文件。
    AspectJ 是一个基于 Java 语言的 AOP 框架,Spring2.0 以后新增了对 AspectJ 切点表达式支持
    @AspectJ  是 AspectJ1.5 新增功能,通过 JDK5 注解技术,允许直接在 Bean 类中定义切面
    新版本 Spring 框架,建议使用 AspectJ 方式来开发 AOP

    • AspectJ 表达式

    在使用spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义pointcut"切入点"。

    execution(<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?)  

    除了返回类型模式、方法名模式和参数模式外,其它项都是可选的

    实例:

    execution (* com.sample.service.impl..*.*(..))
     整个表达式可以分为五个部分:
     1、execution(): 表达式主体。
     2、第一个*号:表示返回类型,*号表示所有的类型。
     3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
     4、第二个*号:表示类名,*号表示所有的类。
     5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
    
    execution(“* cn.spring3.demo1.dao.*(..)”) --- 只匹配当前包
    execution(“* cn.spring3.demo1.dao..*(..)”) --- 匹配包及当前包的子包 .
    execution(* cn.dao.GenericDAO+.*(..)) --- 匹配 GenericDAO 及子类
    execution(* save*(..)) ---匹配所有save开头的方法
    • AspectJ增强方式

    @Before  前置通知,相当于 BeforeAdvice
    @AfterReturning  后置通知,相当于 AfterReturningAdvice
    @Around  环绕通知,相当于 MethodInterceptor
    @AfterThrowing 抛出通知,相当于 ThrowAdvice
    @After  最终 final 通知,不管是否异常,该通知都会执行
    @DeclareParents  引介通知,相当于 IntroductionInterceptor

    一、基于注解的方式

    开发步骤:

    • 第一步 : 引入相应 jar 包
      * aspectj 依赖 aop 环境 .
      * spring-aspects-3.2.0.RELEASE.jar
      * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    • 第二步 : 编写目标类
    • 第三步 : 使用AspectJ注解自定义切面类,就是切点与增强结合
    • 第四步 : 配置XML
      *  引入 aop 的约束 :
      * <aop:aspectj-autoproxy /> ---  自动生成代理 :
      *  底层就是 AnnotationAwareAspectJAutoProxyCreator
    // 类
    public class Student {
        public void add(){
            System.out.println("添加方法...");
        }
    
        public void delete(){
            System.out.println("删除方法...");
        }
    }
    
    // 切面
    @Aspect
    public class MyAspect {
        @Before("execution(* spring2..*.add*(..))")
        void before(){
            System.out.println("前置增强...");
        }
    }
    
    // 测试
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:config3.xml")
    public class Demo {
    
        @Resource(name = "stu")
        private Student s;
        @Test
        public void demo(){
            s.add();
        }
    }
    

    配置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" 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.xsd">
    
         <!--自动生成代理,底层就是 AnnotationAwareAspectJAutoProxyCreator-->
        <aop:aspectj-autoproxy/>
    
        <bean id="stu" class="spring2.Student"/>
    
        <!--需要把切面类进行注册,才能自动生成代理-->
        <bean id="myaspect" class="spring2.MyAspect"/>
    </beans>
    

    * 其他的增强的使用:

    AspectJ的通知类型:
    @Before 前置通知,相当于BeforeAdvice
    * 就在方法之前执行.没有办法阻止目标方法执行的.
    @AfterReturning 后置通知,相当于AfterReturningAdvice
    * 后置通知,获得方法返回值.
    @Around 环绕通知,相当于MethodInterceptor
    * 在可以方法之前和之后来执行的,而且可以阻止目标方法的执行.
    @AfterThrowing 抛出通知,相当于ThrowAdvice
    @After 最终final通知,不管是否异常,该通知都会执行
    @DeclareParents 引介通知,相当于IntroductionInterceptor

    @Aspect
    public class MyAspect {
        @Before("execution(* spring2..*.add*(..))")
        void before() {
            System.out.println("前置增强...");
        }
    
        @AfterReturning(value = "execution(* spring2..*.add*(..))", returning = "returnVal")
        public void afterReturning(Object returnVal) {
            System.out.println("后置增强..." + "方法的返回值:" + returnVal);
        }
    
        @Around("execution(* spring2..*.add*(..))")
        public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕前增强...");
            Object object = proceedingJoinPoint.proceed();
            System.out.println("环绕后增强...");
            return object;
        }
    
        @AfterThrowing(value = "execution(* spring2..*.add*(..))", throwing = "e")
        public void throwing(Throwable e) {
            System.out.println("不好,出异常了!" + e.getMessage());
        }
    
        @After("execution(* spring2..*.add*(..))")
        public void after() {
            System.out.println("最终通知...");
        }
    }
    

    * 基于AspectJ的切点定义

    使用 @Pointcut 进行自定义的切点定义。

    @Aspect
    public class MyAspect {
        @Before("MyAspect.myPointcut()")
        void before() {
            System.out.println("前置增强...");
        }
    
        @Pointcut("execution(* spring2..*.add*(..))")
        private void myPointcut(){}
    }
    

    * Advisor和Aspect的区别

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

    二、基于XML的方式

    /**
     * 切面类
     */
    public class MyAspectXML {
        public void before() {
            System.out.println("前置通知...");
        }
    
        public void afterReturing(Object returnVal) {
            System.out.println("后置通知...返回值:" + returnVal);
        }
    
        public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕前增强....");
            Object result = proceedingJoinPoint.proceed();
            System.out.println("环绕后增强....");
            return result;
        }
    
        public void afterThrowing(Throwable e) {
            System.out.println("异常通知..." + e.getMessage());
        }
    
        public void after() {
            System.out.println("最终通知....");
        }
    }
    

    XML配置:

    <!-- 定义切面 -->
        <bean id="myAspect" class="spring2.MyAspect"></bean>
        <!-- 定义aop配置 -->
        <aop:config>
            <!-- 定义切点: -->
            <aop:pointcut expression="execution(* cn.itcast.spring3.demo2.ProductDao.add(..))" id="mypointcut"/>
            <aop:aspect ref="myAspect">
                <!-- 前置通知 -->
                <!--  <aop:before method="before" pointcut-ref="mypointcut"/> -->
                <!-- 后置通知 -->
                <!-- < aop:after -returning method="afterReturing" pointcut-ref="mypointcut" returning="returnVal"/> -->
                <!-- 环绕通知 -->
                <!-- < aop:around method="around" pointcut-ref="mypointcut"/> -->
                <!-- 异常通知 -->
                <!-- < aop:after-throwing method="afterThrowing" pointcut-ref="mypointcut" throwing="e"/> -->
                <!-- 最终通知 -->
                <aop:after method="after" pointcut-ref="mypointcut"/>
            </aop:aspect>
        </aop:config>
    
  • 相关阅读:
    Docker的安装、配置及其基本使用
    Java提升七:注解
    Java提升六:泛型
    Java提升五:反射与动态代理
    MySQL中如何将主键默认值设为UUID()
    图解Mybatis框架原理及使用
    Java提升四:Stream流
    Java提升三:函数式接口
    Java提升二:Lambda表达式与方法引用
    java提升一:内部类
  • 原文地址:https://www.cnblogs.com/hyserendipity/p/7816812.html
Copyright © 2020-2023  润新知