• 05_Spring AOP原理


    理解AOP相关概念

    Target(目标对象):代理的目标对象

    Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring,这些点指的是方法,因为spring只支持方法类型的连接点.(目标对象中,所有可以增强的方法)

    Pointcut(切入点/切点):所谓切入点是指我们要对哪些Joinpoint进行拦截(目标对象中,确定要增强的方法).

    Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(增强的代码)

    Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程.(将通知应用到切点的过程)

    Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类(将通知织入到目标对象之后,形成代理)

    Aspect(切面): 是切入点和通知的结合(切点+通知)

    一个线是一个特殊的面。

    一个切入点和一个通知,组成成一个特殊的面。

    注意:通知有:  前置通知,后置通知(出现异常不会调用),环绕通知,异常拦截通知,后置通知(出现异常会调用)

    Spring AOP 编程

    从spring容器获得目标类,如果配置aop,spring将自动生成代理。

    导入jar包spring-framework-3.0.2.RELEASE-dependenciesorg.aspectjcom.springsource.org.aspectj.weaver1.6.8.RELEASE

    第一种基于xml配置

    1.配置通知

    
    public class MyAdvice {
    
        //前置通知
        public void before(){
            System.out.println("前置通知");
        }
        //后置通知  出现异常不会调用
        public void afterreturning(){
            System.out.println("后置通知,出现异常不会调用");
        }
        //环绕通知
        public Object around(ProceedingJoinPoint pjp) throws Throwable{
            System.out.println("环绕之前的部分");
            Object obj = pjp.proceed();//调用原方法
            System.out.println("环绕之后的部分");
            return obj;
        }
        //异常拦截通知
        public void afterException(){
            System.out.println("出现异常");
        }
        //后置通知(出现异常会调用)
        public void after(){
            System.out.println("后置通知(出现异常会调用)");
        }
    }
    

    2.配置applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
    	http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
    	http://www.springframework.org/schema/context
    	http://www.springframework.org/schema/context/spring-context-4.2.xsd
    	http://www.springframework.org/schema/aop
    	http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
    	http://www.springframework.org/schema/tx
    	http://www.springframework.org/schema/tx/spring-tx-4.2.xsd ">
        <!-- aop  -->
        <!-- 配置目标对象 -->
        <bean name="userService" class="com.service.userServiceImpl"></bean>
        <!-- 配置通知 -->
        <bean name="myAdvice" class="com.aop.MyAdvice"></bean>
        <!-- 配置通知织入到目标对象的方法 -->
        <aop:config>
            <!-- 配置切入点 即要增强那个方法  -->
            <!-- 方法书写规则:
                com.service.UserServiceImpl.save()
              * com.service.UserServiceImpl.*(..)
              * com.service.*.*(..)
            -->
            <!--切点-->
            <aop:pointcut  expression="execution(public void com.service.userServiceImpl.save())" id="poincut"/> 
            <!-- 切面 -->
            <aop:aspect ref="myAdvice">
                <aop:after method="after" pointcut-ref="poincut"/>
                <aop:after-returning method="afterreturning" pointcut-ref="poincut"/>
                <aop:after-throwing method="afterException" pointcut-ref="poincut"/>
                <aop:around method="around" pointcut-ref="poincut"/>
                <aop:around method="before" pointcut-ref="poincut"/>
            </aop:aspect>
        </aop:config>
    
    </beans>

    测试类demo

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:com/aop/aop.xml")
    public class Demo {
        @Resource(name = "userService")
        private userService userService;
    
        @Test
        public void test(){
            userService.save();
        }
    
    }

    第二种基于Annotation配置

    1.配置通知

    @Component("myAdvice")
    @Aspect
    public class MyAdvice {
        @Pointcut("execution(* com.service.userServiceImpl.*())")
        public void pc(){}
        //前置通知
        @Before("MyAdvice.pc()")
        public void before(){
            System.out.println("前置通知");
        }
        //后置通知  出现异常不会调用
        @AfterReturning("MyAdvice.pc()")
        public void afterreturning(){
            System.out.println("后置通知,出现异常不会调用");
        }
        //环绕通知
        @Around("execution(* com.service.userServiceImpl.*())")
        public Object around(ProceedingJoinPoint pjp) throws Throwable{
            System.out.println("环绕之前的部分");
            Object obj = pjp.proceed();//调用原方法
            System.out.println("环绕之后的部分");
            return obj;
        }
        //异常拦截通知
        @AfterThrowing("execution(* com.service.userServiceImpl.*())")
        public void afterException(){
            System.out.println("出现异常");
        }
        //后置通知(出现异常会调用)
        @After("execution(* com.service.userServiceImpl.*())")
        public void after(){
            System.out.println("后置通知(出现异常会调用)");
        }
    }

    2.配置applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://www.springframework.org/schema/beans"
           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-4.2.xsd
    	   http://www.springframework.org/schema/aop
    	   http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
    	   http://www.springframework.org/schema/context
    	   http://www.springframework.org/schema/context/spring-context.xsd">
        <!-- aop  -->
        <!-- 配置目标对象 -->
        <bean name="userService" class="com.service.userServiceImpl"></bean>
        <!-- 配置通知-->
        <bean name="myAdvice" class="com.aopanotation.MyAdvice"></bean>
        <!-- 使用注解-->
        <context:component-scan base-package="com"></context:component-scan>
        <!-- 配置通知织入到目标对象的方法 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>

    测试代码demo

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:com/aopanotation/aop.xml")
    public class Demo1 {
        @Resource(name = "userService")
        private userService userService;
    
        @Test
        public void test(){
            userService.delete();
        }
    
    }

    @AspectJ 简介

    1.AspectJ是一个基于Java语言的AOP框架,Spring2.0以后新增了对AspectJ切点表达式支持

    2.@AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面

    新版本Spring框架,建议使用AspectJ方式来开发AOP

    使用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

    AOP切入点表达式:execution(掌握)

    AOP切入点表达式支持多种形式的定义规则

    •完整写法

                   返回类型  类的路径     类名   函数名 参数类型(用,分开)

    execution(String com.chinasofti.Target.save(String))

    •任意返回类型

    execution(* com.chin.Target.save(String))

    •任意返回类型下指定包下任意类

    execution(* com.chin.*.save(String))

    •任意返回类型下指定包下任意类任意函数

    execution(* com.chin.*.*(String))

    •任意返回类型下指定包或子包下任意类任意函数任意参数

    execution(* com..*.*(..))

     

     

    AOP通知类型

     before:前置通知(应用:各种校验)

                 在方法执行前执行,如果通知抛出异常,阻止方法运行

     afterReturning:后置通知(应用:常规数据处理)

                 方法正常返回后执行,如果方法中抛出异常,通知无法执行

                 必须在方法执行后才执行,所以可以获得方法的返回值。

     around:环绕通知(应用:十分强大,可以做任何事情)

                 方法执行前后分别执行,可以阻止方法的执行

     afterThrowing:抛出异常通知(应用:包装异常信息)

                 方法抛出异常后执行,如果方法没有抛出异常,无法执行

     after:最终通知(应用:清理现场)

                 方法执行完毕后执行,无论方法中是否出现异常

    AOP核心组件

    切面(Aspect):切面是封装通用业务逻辑的组件,可以作用到其他组件上。

    切入点(Pointcut):用于指定哪些组件哪些方法使用切面组件,Spring提供表达式来实现该指定。

    通知(Advice):用于指定组件作用到目标组件的具体位置。

    AOP前置通知:在目标组件的方法执行前执行的程序。

    完成AOP的步骤

                   切入点程序。

                   切面程序。

                   通过配置文件将切面程序插入到切入点程序的某个位置上(通知)

    补充:jar包

    1.aop联盟规范

    2.spring aop 实现

    3.aspect 规范

    4.spring aspect 实现

  • 相关阅读:
    SQL数据库——存储过程
    常用命令
    八大排序算法
    Java 反射的理解
    Java 集合的理解(持续更新......)
    JAVA 用数组实现 ArrayList
    JVM 运行时的内存分配
    Java中的增强 for 循环 foreach
    Java 泛型
    《七》随机访问文件流
  • 原文地址:https://www.cnblogs.com/jatpeo/p/11767528.html
Copyright © 2020-2023  润新知