zoukankan      html  css  js  c++  java
  • 03Spring的AOP开发

    AOP概念

    概念:Aspect Oriented Programming面向切面编程,是OOP的延续。

    作用:在程序运行期间,在不修改源码情况下,对方法功能增强。

    底层实现:Spring提供的动态代理技术实现:

    • JKD代理:基于接口的动态代理技术(目标对象必须有接口)
    • cglib代理:基于父类的动态代理技术(目标对象可以没有接口)

    两者区别和联系:

    • 两者都是通过一个类来包装另一个类实现代理
    • cglib可以通过配置实现,而不用手动去定义。

    AOP的相关术语:

    • Target(目标对象):代理的目标对象
    • Proxy(代理):一个完成代理的类,返回代理类
    • Joinpoint(连接点):可以被增强的方法(可以被拦截到的方法)
    • Poincut(切入点):被增强的方法(Joinpoint的一部分)
    • Advice(通知/增强):增强方法
    • Aspect(切面):切点+通知(名词)
    • Weaving(织入):将切点和通知结合的过程(动词,创建代理对象的过程)

    AOP重点属于:切点、通知、切面、织入

    AOP需要编写的代码:

    • 编写核心业务代码(目标类、目标方法,目标方法也叫切点)
    • 编写切面类,切面类中有通知(增强方法)
    • 在配置文件中,配置织入关系

    AOP技术原理:

    • Spring框架监控切入点,一旦监控到切入点在执行,动态创建代理对象,在代理对象的对应的位置,将通知方法的功能织入,运行代理对象。

    AOP使用哪种代理方式:

    • 框架根据目标类是否实现了接口来决定采用哪种代理方式。

    XML实现AOP

    1.导入坐标

    <!--    Spring框架-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.0.2.RELEASE</version>
            </dependency>
    <!--     aspectj团队实现的aop配置比较好-->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.6</version>
            </dependency>
    

    2.创建目标类

    创建目标类和接口,以及内部的方法(切点)

    public class MyTarget {
        public void save() {
            System.out.println("save running...");
        }
    }
    

    3.创建通知

    创建切面类,以及增强方法(通知)

    public class MyAspect {
        public void before() {
            System.out.println("前置增强...");
        }
    }
    

    4.织入

    织入:就是在applicationContext.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
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd" >
    <!--目标对象-->
        <bean id="myTarget" class="com.aop.MyTarget"/>
    <!--切面对象-->
        <bean id="myAspect" class="com.aop.MyAspect"/>
    <!--配置织入-->
        <aop:config>
            <aop:aspect ref="myAspect">
                <aop:before method="before" pointcut="execution(public void com.aop.MyTarget.save())"/>
            </aop:aspect>
        </aop:config>
    </beans>
    

    XML配置详解

    <bean id="myTarget" class="com.aop.MyTarget"/>
    <bean id="myAspect" class="com.aop.MyAspect"/>
    <aop:config>
    	<aop:aspect ref="myAspect">
    		<aop:before method="before" pointcut="execution(public void com.aop.MyTarget.save())"/>
    	</aop:aspect>
    </aop:config>
    
    1. 通知的类型:

      • aop:before 前置通知
      • aop:after-returning 后置通知
      • aop:around 环绕通知,前后都执行
      • aop:throwing 异常处理通知,抛出异常时执行
      • aop:after 最终通知,不管抛不抛异常
    2. 切点表达式:execution(public void com.aop.MyTarget.save(参数))

      • 访问限定符可以省略

      • 返回值类型、包名、类名、方法名可以用*号代表任意

      • 包名和类名之间可以一个点.表示当前包下所有类,两个点..表示当前及其子包下的所有类

      • 参数列表可以使用两个点..表示任意个数,任意类型的参数列表

        execution(public void com.aop.MyTarget.method())
        execution(* com.aop.MyTarget.*(..)) // MyTarget下的所有方法
        execution(* com.aop.*.*(..)) // aop包下的所有类的所有方法
        execution(* com.aop..*.*(..)) // aop包下的所有包的所有类的所有方法
        
    3. 切点表达式抽取

      <aop:aspect ref="aspect">
        <aop:pointcut id="myPoint" expression="execution(* com.aop..*.*(..))"/>
        <aop:before method="before" pointcut-ref="myPoint"/>
      </aop:aspect>
      

    注解实现AOP

    导入坐标

    <!--    Spring框架-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.0.2.RELEASE</version>
            </dependency>
    <!--     aspectj团队实现的aop配置比较好-->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.6</version>
            </dependency>
    <!--        spring-test-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.0.2.RELEASE</version>
            </dependency>
    

    步骤:

    1. 创建目标接口和类,添加注解@Component("xx"),表示交给spring框架

    2. 创建切面类,添加注解@Component("xxx"),表示交给spring框架

    3. 在切面类中使用注解配置织入关系:类上加@Aspect表示切面,方法上添加注解类型

      @Component("myAspect")
      @Aspect
      public class MyAspect {
          @Before("execution(void com.aop.MyTarget.save())")
          public void before() {
              System.out.println("前置增强...");
          }
      }
      
    4. 在applicationContext配置文件中开启组件扫描和AOP的自动代理

      <?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"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
              https://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/aop
              https://www.springframework.org/schema/aop/spring-aop.xsd
              http://www.springframework.org/schema/context
              https://www.springframework.org/schema/context/spring-context.xsd" >
      
      <!--    组件扫描-->
          <context:component-scan base-package="com.aop"/>
      <!--    aop自动代理-->
          <aop:aspectj-autoproxy/>
      
      </beans>
      
    5. 测试(创建一个目标类并执行)

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration("classpath:applicationContext-anno.xml")
      public class SpringTest {
          @Autowired
          private MyTarget target;
          @Test
          public void test01() throws SQLException {
              target.save();
          }
      }
      

    注解详解

    1. 通知的类型 @通知("切点表达式")

      • Before, AfterReturning Around AfterThrowing After
    2. 切点表达式的抽取

      @Component("myAspect")
      @org.aspectj.lang.annotation.Aspect
      public class Aspect {
          @Before("pointchut()")
          public void before() {
              System.out.println("before");
          }
          @Poincut("execution(void baidu.proxy.cglib.Target.save())")
          public void pointcut(){}
      }
      
  • 相关阅读:
    【TJOI2019 Day2】简要题解
    【TJOI2019 Day2】简要题解
    【Codeforces 750G】—New Year and Binary Tree Paths(数位dp)
    【Codeforces 750G】—New Year and Binary Tree Paths(数位dp)
    【TJOI2019 Day1】简要题解
    【TJOI2019 Day1】简要题解
    【LOJ #6503】【雅礼集训 2018 Day4】—Magic(生成函数+分治NTT)
    【LOJ #6503】【雅礼集训 2018 Day4】—Magic(生成函数+分治NTT)
    【HihoCoder #1529】— 不上升序列(dp+斜率)
    【HihoCoder #1529】— 不上升序列(dp+斜率)
  • 原文地址:https://www.cnblogs.com/mingriyingying/p/13639508.html
Copyright © 2011-2022 走看看